summaryrefslogtreecommitdiff
path: root/apps/plugins/midi/synth.c
diff options
context:
space:
mode:
authorStepan Moskovchenko <stevenm@rockbox.org>2007-10-15 05:11:37 +0000
committerStepan Moskovchenko <stevenm@rockbox.org>2007-10-15 05:11:37 +0000
commit1515ff852224c822a6d3db8c458eab2c9037704f (patch)
treee427fbec1b397d18abffc12b7fe74e67c2cad807 /apps/plugins/midi/synth.c
parent99f955088149d5938ce4c9ca5624377f464b1380 (diff)
downloadrockbox-1515ff852224c822a6d3db8c458eab2c9037704f.tar.gz
rockbox-1515ff852224c822a6d3db8c458eab2c9037704f.zip
MIDI: At long last, though quick and dirty, pitch bend depth! Or, I think it works. Tested on two
files. Let me know if anyone discovers any problems with this. This commit also includes Nils's synth loop optimization patch. I hope committing it does not cause problems. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15112 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/midi/synth.c')
-rw-r--r--apps/plugins/midi/synth.c261
1 files changed, 133 insertions, 128 deletions
diff --git a/apps/plugins/midi/synth.c b/apps/plugins/midi/synth.c
index 568c7bb1ce..f0fa93d60e 100644
--- a/apps/plugins/midi/synth.c
+++ b/apps/plugins/midi/synth.c
@@ -65,6 +65,7 @@ int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig)
65 chPan[a]=64; /* Center */ 65 chPan[a]=64; /* Center */
66 chPat[a]=0; /* Ac Gr Piano */ 66 chPat[a]=0; /* Ac Gr Piano */
67 chPW[a]=256; /* .. not .. bent ? */ 67 chPW[a]=256; /* .. not .. bent ? */
68 chPBDepth[a]=2; /* Default bend value is 2 */
68 } 69 }
69 for(a=0; a<128; a++) 70 for(a=0; a<128; a++)
70 { 71 {
@@ -255,191 +256,195 @@ inline void stopVoice(struct SynthObject * so)
255 so->decay = 0; 256 so->decay = 0;
256} 257}
257 258
258static inline int synthVoice(struct SynthObject * so) 259static inline void synthVoice(struct SynthObject * so, int32_t * out, unsigned int samples)
259{ 260{
260 struct GWaveform * wf; 261 struct GWaveform * wf;
261 register int s; 262 register int s;
262 register unsigned int cpShifted; 263 register int s1;
263 register short s1; 264 register int s2;
264 register short s2; 265
266 register unsigned int cp_temp = so->cp;
265 267
266 wf = so->wf; 268 wf = so->wf;
267 269
270 const int mode_mask24 = wf->mode&24;
271 const int mode_mask28 = wf->mode&28;
272 const int mode_mask_looprev = wf->mode&LOOP_REVERSE;
268 273
269 /* Is voice being ramped? */ 274 const unsigned int num_samples = (wf->numSamples-1) << FRACTSIZE;
270 if(so->state == STATE_RAMPDOWN)
271 {
272 if(so->decay != 0) /* Ramp has been started */
273 {
274 so->decay = so->decay / 2;
275 275
276 if(so->decay < 10 && so->decay > -10) 276 const unsigned int end_loop = wf->endLoop << FRACTSIZE;
277 so->isUsed = 0; 277 const unsigned int start_loop = wf->startLoop << FRACTSIZE;
278 const int diff_loop = end_loop-start_loop;
278 279
279 return so->decay; 280 while(samples > 0)
280 }
281 } else /* OK to advance voice */
282 { 281 {
283 so->cp += so->delta; 282 samples--;
284 } 283 /* Is voice being ramped? */
285 284 if(so->state == STATE_RAMPDOWN)
286 285 {
287 cpShifted = so->cp >> FRACTSIZE; 286 if(so->decay != 0) /* Ramp has been started */
287 {
288 so->decay = so->decay / 2;
288 289
290 if(so->decay < 10 && so->decay > -10)
291 so->isUsed = 0;
289 292
293 s1=so->decay;
294 s2 = s1*chPan[so->ch];
295 s1 = (s1<<7) -s2;
296 *(out++)+=(((s1&0x7FFF80) << 9) | ((s2&0x7FFF80) >> 7));
297 continue;
298 }
299 } else /* OK to advance voice */
300 {
301 cp_temp += so->delta;
302 }
290 303
291 s2 = getSample((cpShifted)+1, wf); 304 s2 = getSample((cp_temp >> FRACTSIZE)+1, wf);
292 305
293 /* LOOP_REVERSE|LOOP_PINGPONG = 24 */ 306 /* LOOP_REVERSE|LOOP_PINGPONG = 24 */
294 if((wf->mode & (24)) && so->loopState == STATE_LOOPING && (cpShifted < (wf->startLoop))) 307 if(mode_mask24 && so->loopState == STATE_LOOPING && (cp_temp < start_loop))
295 {
296 if(wf->mode & LOOP_REVERSE)
297 {
298 cpShifted = wf->endLoop-(wf->startLoop-cpShifted);
299 so->cp = (cpShifted)<<FRACTSIZE;
300 s2=getSample((cpShifted), wf);
301 }
302 else
303 { 308 {
304 so->delta = -so->delta; /* At this point cpShifted is wrong. We need to take a step */ 309 if(mode_mask_looprev)
305 so->loopDir = LOOPDIR_FORWARD; 310 {
311 cp_temp += diff_loop;
312 s2=getSample((cp_temp >> FRACTSIZE), wf);
313 }
314 else
315 {
316 so->delta = -so->delta; /* At this point cp_temp is wrong. We need to take a step */
317 so->loopDir = LOOPDIR_FORWARD;
318 }
306 } 319 }
307 }
308 320
309 if((wf->mode & 28) && (cpShifted >= wf->endLoop)) 321 if(mode_mask28 && (cp_temp >= end_loop))
310 {
311 so->loopState = STATE_LOOPING;
312 if((wf->mode & (24)) == 0)
313 { 322 {
314 cpShifted = wf->startLoop + (cpShifted-wf->endLoop); 323 so->loopState = STATE_LOOPING;
315 so->cp = (cpShifted)<<FRACTSIZE; 324 if(!mode_mask24)
316 s2=getSample((cpShifted), wf); 325 {
326 cp_temp -= diff_loop;
327 s2=getSample((cp_temp >> FRACTSIZE), wf);
328 }
329 else
330 {
331 so->delta = -so->delta;
332 so->loopDir = LOOPDIR_REVERSE;
333 }
317 } 334 }
318 else 335
336 /* Have we overrun? */
337 if(cp_temp >= num_samples)
319 { 338 {
320 so->delta = -so->delta; 339 cp_temp -= so->delta;
321 so->loopDir = LOOPDIR_REVERSE; 340 s2 = getSample((cp_temp >> FRACTSIZE)+1, wf);
341 stopVoice(so);
322 } 342 }
323 }
324
325 /* Have we overrun? */
326 if( (cpShifted >= (wf->numSamples-1)))
327 {
328 so->cp -= so->delta;
329 cpShifted = so->cp >> FRACTSIZE;
330 s2 = getSample((cpShifted)+1, wf);
331 stopVoice(so);
332 }
333
334
335 /* Better, working, linear interpolation */
336 s1=getSample((cpShifted), wf);
337 343
338 s = s1 + ((signed)((s2 - s1) * (so->cp & ((1<<FRACTSIZE)-1)))>>FRACTSIZE); 344 /* Better, working, linear interpolation */
345 s1=getSample((cp_temp >> FRACTSIZE), wf);
339 346
347 s = s1 + ((signed)((s2 - s1) * (cp_temp & ((1<<FRACTSIZE)-1)))>>FRACTSIZE);
340 348
341 if(so->curRate == 0) 349 if(so->curRate == 0)
342 { 350 {
343 stopVoice(so); 351 stopVoice(so);
344// so->isUsed = 0; 352// so->isUsed = 0;
345 353
346 } 354 }
347 355
348 if(so->ch != 9 && so->state != STATE_RAMPDOWN) /* Stupid ADSR code... and don't do ADSR for drums */ 356 if(so->ch != 9 && so->state != STATE_RAMPDOWN) /* Stupid ADSR code... and don't do ADSR for drums */
349 {
350 if(so->curOffset < so->targetOffset)
351 { 357 {
352 so->curOffset += (so->curRate); 358 if(so->curOffset < so->targetOffset)
353 if(so -> curOffset > so->targetOffset && so->curPoint != 2)
354 { 359 {
355 if(so->curPoint != 5) 360 so->curOffset += (so->curRate);
361 if(so -> curOffset > so->targetOffset && so->curPoint != 2)
356 { 362 {
357 setPoint(so, so->curPoint+1); 363 if(so->curPoint != 5)
364 {
365 setPoint(so, so->curPoint+1);
366 }
367 else
368 {
369 stopVoice(so);
370 }
358 } 371 }
359 else 372 } else
373 {
374 so->curOffset -= (so->curRate);
375 if(so -> curOffset < so->targetOffset && so->curPoint != 2)
360 { 376 {
361 stopVoice(so); 377
378 if(so->curPoint != 5)
379 {
380 setPoint(so, so->curPoint+1);
381 }
382 else
383 {
384 stopVoice(so);
385 }
386
362 } 387 }
363 } 388 }
364 } else 389 }
390
391 if(so->curOffset < 0)
365 { 392 {
366 so->curOffset -= (so->curRate); 393 so->curOffset = so->targetOffset;
367 if(so -> curOffset < so->targetOffset && so->curPoint != 2) 394 stopVoice(so);
368 { 395 }
369 396
370 if(so->curPoint != 5) 397 s = (s * (so->curOffset >> 22) >> 8);
371 {
372 setPoint(so, so->curPoint+1);
373 }
374 else
375 {
376 stopVoice(so);
377 }
378 398
379 } 399 /* need to set ramp beginning */
400 if(so->state == STATE_RAMPDOWN && so->decay == 0)
401 {
402 so->decay = s*so->volscale>>14;
403 if(so->decay == 0)
404 so->decay = 1; /* stupid junk.. */
380 } 405 }
381 }
382 406
383 if(so->curOffset < 0)
384 {
385 so->curOffset = so->targetOffset;
386 stopVoice(so);
387 }
388 407
389 s = (s * (so->curOffset >> 22) >> 8); 408 /* Scaling by channel volume and note volume is done in sequencer.c */
409 /* That saves us some multiplication and pointer operations */
410 s1=s*so->volscale>>14;
390 411
412 s2 = s1*chPan[so->ch];
413 s1 = (s1<<7) - s2;
414 *(out++)+=(((s1&0x7FFF80) << 9) | ((s2&0x7FFF80) >> 7));
391 415
392 /* need to set ramp beginning */
393 if(so->state == STATE_RAMPDOWN && so->decay == 0)
394 {
395 so->decay = s*so->volscale>>14;
396 if(so->decay == 0)
397 so->decay = 1; /* stupid junk.. */
398 } 416 }
399 417
400 418 so->cp=cp_temp; /* store this again */
401 /* Scaling by channel volume and note volume is done in sequencer.c */ 419 return;
402 /* That saves us some multiplication and pointer operations */
403 return s*so->volscale>>14;
404} 420}
405 421
422/* buffer to hold all the samples for the current tick, this is a hack
423 neccesary for coldfire targets as pcm_play_data uses the dma which cannot
424 access iram */
425int32_t samp_buf[256] IBSS_ATTR;
426
406/* synth num_samples samples and write them to the */ 427/* synth num_samples samples and write them to the */
407/* buffer pointed to by buf_ptr */ 428/* buffer pointed to by buf_ptr */
408void synthSamples(int32_t *buf_ptr, unsigned int num_samples) ICODE_ATTR; 429void synthSamples(int32_t *buf_ptr, unsigned int num_samples) ICODE_ATTR;
409void synthSamples(int32_t *buf_ptr, unsigned int num_samples) 430void synthSamples(int32_t *buf_ptr, unsigned int num_samples)
410{ 431{
411 int i; 432 int i;
412 register int dL; 433 struct SynthObject *voicept;
413 register int dR; 434
414 register int sample; 435 rb->memset(samp_buf, 0, num_samples*4);
415 register struct SynthObject *voicept;
416 while(num_samples>0)
417 {
418 dL=0;
419 dR=0;
420 voicept=&voices[0];
421 436
422 for(i=MAX_VOICES; i > 0; i--) 437 for(i=0; i < MAX_VOICES; i++)
438 {
439 voicept=&voices[i];
440 if(voicept->isUsed==1)
423 { 441 {
424 if(voicept->isUsed==1) 442 synthVoice(voicept, samp_buf, num_samples);
425 {
426 sample = synthVoice(voicept);
427 dL += sample;
428 sample *= chPan[voicept->ch];
429 dR += sample;
430 }
431 voicept++;
432 } 443 }
444 }
433 445
434 dL = (dL << 7) - dR; 446 rb->memcpy(buf_ptr, samp_buf, num_samples*4);
435
436 /* combine the left and right 16 bit samples into 32 bits and write */
437 /* to the buffer, left sample in the high word and right in the low word */
438 *buf_ptr=(((dL&0x7FFF80) << 9) | ((dR&0x7FFF80) >> 7));
439 447
440 buf_ptr++;
441 num_samples--;
442 }
443 /* TODO: Automatic Gain Control, anyone? */ 448 /* TODO: Automatic Gain Control, anyone? */
444 /* Or, should this be implemented on the DSP's output volume instead? */ 449 /* Or, should this be implemented on the DSP's output volume instead? */
445 450