1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 Stepan Moskovchenko
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
26 void readTextBlock(int file
, char * buf
)
32 } while(c
== '\n' || c
== ' ' || c
=='\t');
34 rb
->lseek(file
, -1, SEEK_CUR
);
41 } while (c
!= '\n' && c
!= ' ' && c
!= '\t' && !eof(file
));
43 rb
->lseek(file
, -1, SEEK_CUR
);
46 void resetControllers()
49 for(a
=0; a
<MAX_VOICES
; a
++)
54 voices
[a
].isUsed
=false;
60 chVol
[a
]=100; /* Default, not quite full blast.. */
61 chPan
[a
]=64; /* Center */
62 chPat
[a
]=0; /* Ac Gr Piano */
63 chPW
[a
]=256; /* .. not .. bent ? */
64 chPBDepth
[a
]=2; /* Default bend value is 2 */
65 chPBNoteOffset
[a
]=0; /* No offset */
66 chPBFractBend
[a
]=65536; /* Center.. no bend */
67 chLastCtrlMSB
[a
]=0; /* Set to pitch bend depth */
68 chLastCtrlLSB
[a
]=0; /* Set to pitch bend depth */
72 /* Filename is the name of the config file */
73 /* The MIDI file should have been loaded at this point */
74 int initSynth(struct MIDIfile
* mf
, char * filename
, char * drumConfig
)
91 * Always load the piano.
92 * Some files will assume its loaded without specifically
93 * issuing a Patch command... then we wonder why we can't hear anything
97 /* Scan the file to see what needs to be loaded */
100 for(a
=0; a
<mf
->numTracks
; a
++)
104 if(mf
->tracks
[a
] == NULL
)
106 printf("NULL TRACK !!!");
107 rb
->splash(HZ
*2, "Null Track in loader.");
111 for(ts
=0; ts
<mf
->tracks
[a
]->numEvents
; ts
++)
114 if((getEvent(mf
->tracks
[a
], ts
)->status
) == (MIDI_NOTE_ON
+9))
115 drumUsed
[getEvent(mf
->tracks
[a
], ts
)->d1
]=1;
117 if( (getEvent(mf
->tracks
[a
], ts
)->status
& 0xF0) == MIDI_PRGM
)
118 patchUsed
[getEvent(mf
->tracks
[a
], ts
)->d1
]=1;
123 /* Initialize the whole drum set */
129 int file
= rb
->open(filename
, O_RDONLY
);
133 printf("No MIDI patchset found.");
134 printf("Please install the instruments.");
135 printf("See Rockbox page for more info.");
137 rb
->splash(HZ
*2, "No Instruments");
144 /* Scan our config file and load the right patches as needed */
147 printf("Loading instruments");
150 while(readChar(file
)!=' ' && !eof(file
));
151 readTextBlock(file
, name
);
153 rb
->snprintf(fn
, 40, ROCKBOX_DIR
"/patchset/%s.pat", name
);
154 /* printf("\nLOADING: <%s> ", fn); */
158 patchSet
[a
]=gusload(fn
);
160 if(patchSet
[a
] == NULL
) /* There was an error loading it */
169 file
= rb
->open(drumConfig
, O_RDONLY
);
172 rb
->splash(HZ
*2, "Bad drum config. Did you install the patchset?");
176 /* Scan our config file and load the drum data */
179 printf("Loading drums");
182 readTextBlock(file
, number
);
183 readTextBlock(file
, name
);
184 rb
->snprintf(fn
, 40, ROCKBOX_DIR
"/patchset/%s.pat", name
);
186 idx
= rb
->atoi(number
);
192 drumSet
[idx
]=gusload(fn
);
193 if(drumSet
[idx
] == NULL
) /* Error loading patch */
197 while((c
!= '\n') && (c
!= 255) && (!eof(file
)))
204 #define getSample(s,wf) ((short *)(wf)->data)[s]
206 void setPoint(struct SynthObject
* so
, int pt
) ICODE_ATTR
;
207 void setPoint(struct SynthObject
* so
, int pt
)
209 if(so
->ch
==9) /* Drums, no ADSR */
211 so
->curOffset
= 1<<27;
218 printf("Crap... null waveform...");
221 if(so
->wf
->envRate
==NULL
)
223 printf("Waveform has no envelope set");
230 int rate
= so
->wf
->envRate
[pt
];
232 r
=3-((rate
>>6) & 0x3); /* Some blatant Timidity code for rate conversion... */
234 r
= (rate
& 0x3f) << r
;
237 * Okay. This is the rate shift. Timidity defaults to 9, and sets
238 * it to 10 if you use the fast decay option. Slow decay sounds better
239 * on some files, except on some other files... you get chords that aren't
240 * done decaying yet.. and they dont harmonize with the next chord and it
241 * sounds like utter crap. Yes, even Timitidy does that. So I'm going to
242 * default this to 10, and maybe later have an option to set it to 9
248 * Do this here because the patches assume a 44100 sampling rate
249 * We've halved our sampling rate, ergo the ADSR code will be
250 * called half the time. Ergo, double the rate to keep stuff
253 * Or just move the 1 up one line to optimize a tiny bit.
255 /* so->curRate = so->curRate << 1; */
258 so
->targetOffset
= so
->wf
->envOffset
[pt
]<<(20);
263 static inline void synthVoice(struct SynthObject
* so
, int32_t * out
, unsigned int samples
)
265 struct GWaveform
* wf
;
269 register unsigned int cp_temp
= so
->cp
;
273 const unsigned int pan
= chPan
[so
->ch
];
274 const int volscale
= so
->volscale
;
276 const int mode_mask24
= wf
->mode
&24;
277 const int mode_mask28
= wf
->mode
&28;
278 const int mode_mask_looprev
= wf
->mode
&LOOP_REVERSE
;
280 const unsigned int num_samples
= (wf
->numSamples
-1) << FRACTSIZE
;
282 const unsigned int end_loop
= wf
->endLoop
<< FRACTSIZE
;
283 const unsigned int start_loop
= wf
->startLoop
<< FRACTSIZE
;
284 const int diff_loop
= end_loop
-start_loop
;
286 bool rampdown
= (so
->state
== STATE_RAMPDOWN
);
287 const bool ch_9
= (so
->ch
== 9);
289 while(LIKELY(samples
-- > 0))
291 /* Is voice being ramped? */
292 if(UNLIKELY(rampdown
))
294 if(so
->decay
!= 0) /* Ramp has been started */
296 so
->decay
= so
->decay
/ 2;
298 if(so
->decay
< 10 && so
->decay
> -10)
304 *(out
++) += ((s1
<< 9) & 0xFFFF0000) | ((s2
>> 7) &0xFFFF);
307 } else /* OK to advance voice */
309 cp_temp
+= so
->delta
;
312 s2
= getSample((cp_temp
>> FRACTSIZE
)+1, wf
);
314 if(LIKELY(mode_mask28
))
316 /* LOOP_REVERSE|LOOP_PINGPONG = 24 */
317 if(UNLIKELY(mode_mask24
&& so
->loopState
== STATE_LOOPING
&& (cp_temp
< start_loop
)))
319 if(UNLIKELY(mode_mask_looprev
))
321 cp_temp
+= diff_loop
;
322 s2
=getSample((cp_temp
>> FRACTSIZE
), wf
);
326 so
->delta
= -so
->delta
; /* At this point cp_temp is wrong. We need to take a step */
330 if(UNLIKELY(cp_temp
>= end_loop
))
332 so
->loopState
= STATE_LOOPING
;
333 if(UNLIKELY(!mode_mask24
))
335 cp_temp
-= diff_loop
;
336 s2
=getSample((cp_temp
>> FRACTSIZE
), wf
);
340 so
->delta
= -so
->delta
;
345 /* Have we overrun? */
346 if(UNLIKELY(cp_temp
>= num_samples
))
348 cp_temp
-= so
->delta
;
349 s2
= getSample((cp_temp
>> FRACTSIZE
)+1, wf
);
351 if (!rampdown
) /* stop voice */
358 /* Better, working, linear interpolation */
359 s1
=getSample((cp_temp
>> FRACTSIZE
), wf
);
361 s1
+=((signed)((s2
- s1
) * (cp_temp
& ((1<<FRACTSIZE
)-1)))>>FRACTSIZE
);
363 if(UNLIKELY(so
->curRate
== 0))
365 if (!rampdown
) /* stop voice */
370 // so->isUsed = false;
373 if(LIKELY(!ch_9
&& !rampdown
)) /* Stupid ADSR code... and don't do ADSR for drums */
375 if(UNLIKELY(so
->curOffset
< so
->targetOffset
))
377 so
->curOffset
+= (so
->curRate
);
378 if(UNLIKELY(so
-> curOffset
> so
->targetOffset
&& so
->curPoint
!= 2))
380 if(UNLIKELY(so
->curPoint
!= 5))
382 setPoint(so
, so
->curPoint
+1);
384 else if (!rampdown
) /* stop voice */
392 so
->curOffset
-= (so
->curRate
);
393 if(UNLIKELY(so
-> curOffset
< so
->targetOffset
&& so
->curPoint
!= 2))
395 if(UNLIKELY(so
->curPoint
!= 5))
397 setPoint(so
, so
->curPoint
+1);
399 else if (!rampdown
) /* stop voice */
409 if(UNLIKELY(so
->curOffset
< 0))
411 so
->curOffset
= so
->targetOffset
;
419 s1
= s1
* (so
->curOffset
>> 22) >> 8;
421 /* Scaling by channel volume and note volume is done in sequencer.c */
422 /* That saves us some multiplication and pointer operations */
423 s1
= s1
* volscale
>> 14;
425 /* need to set ramp beginning */
426 if(UNLIKELY(rampdown
&& so
->decay
== 0))
430 so
->decay
= 1; /* stupid junk.. */
435 *(out
++) += ((s1
<< 9) & 0xFFFF0000) | ((s2
>> 7) &0xFFFF);
438 /* store these again */
440 so
->state
= STATE_RAMPDOWN
;
445 /* buffer to hold all the samples for the current tick, this is a hack
446 neccesary for coldfire targets as pcm_play_data uses the dma which cannot
448 int32_t samp_buf
[512] IBSS_ATTR
;
450 /* synth num_samples samples and write them to the */
451 /* buffer pointed to by buf_ptr */
452 void synthSamples(int32_t *buf_ptr
, unsigned int num_samples
) ICODE_ATTR
;
453 void synthSamples(int32_t *buf_ptr
, unsigned int num_samples
)
455 if (UNLIKELY(num_samples
> 512))
456 DEBUGF("num_samples is too big!\n");
460 struct SynthObject
*voicept
;
462 rb
->memset(samp_buf
, 0, num_samples
*4);
464 for(i
=0; i
< MAX_VOICES
; i
++)
469 synthVoice(voicept
, samp_buf
, num_samples
);
473 rb
->memcpy(buf_ptr
, samp_buf
, num_samples
*4);
476 /* TODO: Automatic Gain Control, anyone? */
477 /* Or, should this be implemented on the DSP's output volume instead? */
479 return; /* No more ghetto lowpass filter. Linear interpolation works well. */