diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2019-08-04 16:58:20 -0400 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2019-08-05 20:48:40 +0200 |
commit | ed724fecb15d90d8075ed1edb963f455cb91b0a1 (patch) | |
tree | 6b72250278e5170bc7ed4b8263f48eb8e8dc1c61 | |
parent | eea5bfc9aec35686406296641b37bcc2c731fbbb (diff) | |
download | rockbox-ed724fecb15d90d8075ed1edb963f455cb91b0a1.tar.gz rockbox-ed724fecb15d90d8075ed1edb963f455cb91b0a1.zip |
Midiplay plugin ehancements
- Improved robustness
- Improved sound quality
- Use mixer and DSP
Patch by Igor Poretsky
Change-Id: I6fa617158cbaa53ae842295cdbdbe3a478e49ded
-rw-r--r-- | apps/plugins/midi/guspat.c | 60 | ||||
-rw-r--r-- | apps/plugins/midi/midifile.c | 23 | ||||
-rw-r--r-- | apps/plugins/midi/midiplay.c | 174 | ||||
-rw-r--r-- | apps/plugins/midi/midiutil.c | 38 | ||||
-rw-r--r-- | apps/plugins/midi/midiutil.h | 5 | ||||
-rw-r--r-- | apps/plugins/midi/synth.c | 41 | ||||
-rw-r--r-- | apps/plugins/midi/synth.h | 2 |
7 files changed, 230 insertions, 113 deletions
diff --git a/apps/plugins/midi/guspat.c b/apps/plugins/midi/guspat.c index f650555520..d94fbce021 100644 --- a/apps/plugins/midi/guspat.c +++ b/apps/plugins/midi/guspat.c | |||
@@ -66,6 +66,8 @@ static struct GWaveform * loadWaveform(int file) | |||
66 | rb->memset(wav, 0, sizeof(struct GWaveform)); | 66 | rb->memset(wav, 0, sizeof(struct GWaveform)); |
67 | 67 | ||
68 | wav->name=readData(file, 7); | 68 | wav->name=readData(file, 7); |
69 | if (!wav->name) | ||
70 | return NULL; | ||
69 | /* printf("\nWAVE NAME = [%s]", wav->name); */ | 71 | /* printf("\nWAVE NAME = [%s]", wav->name); */ |
70 | wav->fractions=readChar(file); | 72 | wav->fractions=readChar(file); |
71 | wav->wavSize=readDWord(file); | 73 | wav->wavSize=readDWord(file); |
@@ -81,7 +83,11 @@ static struct GWaveform * loadWaveform(int file) | |||
81 | 83 | ||
82 | wav->balance=readChar(file); | 84 | wav->balance=readChar(file); |
83 | wav->envRate=readData(file, 6); | 85 | wav->envRate=readData(file, 6); |
86 | if (!wav->envRate) | ||
87 | return NULL; | ||
84 | wav->envOffset=readData(file, 6); | 88 | wav->envOffset=readData(file, 6); |
89 | if (!wav->envOffset) | ||
90 | return NULL; | ||
85 | 91 | ||
86 | wav->tremSweep=readChar(file); | 92 | wav->tremSweep=readChar(file); |
87 | wav->tremRate=readChar(file); | 93 | wav->tremRate=readChar(file); |
@@ -95,7 +101,11 @@ static struct GWaveform * loadWaveform(int file) | |||
95 | wav->scaleFactor=readWord(file); | 101 | wav->scaleFactor=readWord(file); |
96 | /* printf("\nScaleFreq = %d ScaleFactor = %d RootFreq = %d", wav->scaleFreq, wav->scaleFactor, wav->rootFreq); */ | 102 | /* printf("\nScaleFreq = %d ScaleFactor = %d RootFreq = %d", wav->scaleFreq, wav->scaleFactor, wav->rootFreq); */ |
97 | wav->res=readData(file, 36); | 103 | wav->res=readData(file, 36); |
104 | if (!wav->res) | ||
105 | return NULL; | ||
98 | wav->data=readData(file, wav->wavSize); | 106 | wav->data=readData(file, wav->wavSize); |
107 | if (!wav->data) | ||
108 | return NULL; | ||
99 | 109 | ||
100 | wav->numSamples = wav->wavSize / 2; | 110 | wav->numSamples = wav->wavSize / 2; |
101 | wav->startLoop = wav->startLoop >> 1; | 111 | wav->startLoop = wav->startLoop >> 1; |
@@ -166,7 +176,10 @@ static int selectWaveform(struct GPatch * pat, int midiNote) | |||
166 | struct GPatch * gusload(char * filename) | 176 | struct GPatch * gusload(char * filename) |
167 | { | 177 | { |
168 | struct GPatch * gp = (struct GPatch *)malloc(sizeof(struct GPatch)); | 178 | struct GPatch * gp = (struct GPatch *)malloc(sizeof(struct GPatch)); |
169 | rb->memset(gp, 0, sizeof(struct GPatch)); | 179 | |
180 | if (gp) | ||
181 | rb->memset(gp, 0, sizeof(struct GPatch)); | ||
182 | else return NULL; | ||
170 | 183 | ||
171 | int file = rb->open(filename, O_RDONLY); | 184 | int file = rb->open(filename, O_RDONLY); |
172 | 185 | ||
@@ -179,8 +192,23 @@ struct GPatch * gusload(char * filename) | |||
179 | } | 192 | } |
180 | 193 | ||
181 | gp->header=readData(file, 12); | 194 | gp->header=readData(file, 12); |
195 | if (!gp->header) | ||
196 | { | ||
197 | rb->close(file); | ||
198 | return NULL; | ||
199 | } | ||
182 | gp->gravisid=readData(file, 10); | 200 | gp->gravisid=readData(file, 10); |
201 | if (!gp->gravisid) | ||
202 | { | ||
203 | rb->close(file); | ||
204 | return NULL; | ||
205 | } | ||
183 | gp->desc=readData(file, 60); | 206 | gp->desc=readData(file, 60); |
207 | if (!gp->desc) | ||
208 | { | ||
209 | rb->close(file); | ||
210 | return NULL; | ||
211 | } | ||
184 | gp->inst=readChar(file); | 212 | gp->inst=readChar(file); |
185 | gp->voc=readChar(file); | 213 | gp->voc=readChar(file); |
186 | gp->chan=readChar(file); | 214 | gp->chan=readChar(file); |
@@ -188,28 +216,52 @@ struct GPatch * gusload(char * filename) | |||
188 | gp->vol=readWord(file); | 216 | gp->vol=readWord(file); |
189 | gp->datSize=readDWord(file); | 217 | gp->datSize=readDWord(file); |
190 | gp->res=readData(file, 36); | 218 | gp->res=readData(file, 36); |
219 | if (!gp->res) | ||
220 | { | ||
221 | rb->close(file); | ||
222 | return NULL; | ||
223 | } | ||
191 | 224 | ||
192 | gp->instrID=readWord(file); | 225 | gp->instrID=readWord(file); |
193 | gp->instrName=readData(file,16); | 226 | gp->instrName=readData(file,16); |
227 | if (!gp->instrName) | ||
228 | { | ||
229 | rb->close(file); | ||
230 | return NULL; | ||
231 | } | ||
194 | gp->instrSize=readDWord(file); | 232 | gp->instrSize=readDWord(file); |
195 | gp->layers=readChar(file); | 233 | gp->layers=readChar(file); |
196 | gp->instrRes=readData(file,40); | 234 | gp->instrRes=readData(file,40); |
197 | 235 | if (!gp->instrRes) | |
236 | { | ||
237 | rb->close(file); | ||
238 | return NULL; | ||
239 | } | ||
198 | 240 | ||
199 | gp->layerDup=readChar(file); | 241 | gp->layerDup=readChar(file); |
200 | gp->layerID=readChar(file); | 242 | gp->layerID=readChar(file); |
201 | gp->layerSize=readDWord(file); | 243 | gp->layerSize=readDWord(file); |
202 | gp->numWaves=readChar(file); | 244 | gp->numWaves=readChar(file); |
203 | gp->layerRes=readData(file,40); | 245 | gp->layerRes=readData(file,40); |
204 | 246 | if (!gp->layerRes) | |
247 | { | ||
248 | rb->close(file); | ||
249 | return NULL; | ||
250 | } | ||
205 | 251 | ||
206 | /* printf("\nFILE: %s", filename); */ | 252 | /* printf("\nFILE: %s", filename); */ |
207 | /* printf("\nlayerSamples=%d", gp->numWaves); */ | 253 | /* printf("\nlayerSamples=%d", gp->numWaves); */ |
208 | 254 | ||
209 | int a=0; | 255 | int a=0; |
210 | for(a=0; a<gp->numWaves; a++) | 256 | for(a=0; a<gp->numWaves; a++) |
257 | { | ||
211 | gp->waveforms[a] = loadWaveform(file); | 258 | gp->waveforms[a] = loadWaveform(file); |
212 | 259 | if (!gp->waveforms[a]) | |
260 | { | ||
261 | rb->close(file); | ||
262 | return NULL; | ||
263 | } | ||
264 | } | ||
213 | 265 | ||
214 | /* printf("\nPrecomputing note table"); */ | 266 | /* printf("\nPrecomputing note table"); */ |
215 | 267 | ||
diff --git a/apps/plugins/midi/midifile.c b/apps/plugins/midi/midifile.c index 86544fd944..2340c6d14f 100644 --- a/apps/plugins/midi/midifile.c +++ b/apps/plugins/midi/midifile.c | |||
@@ -106,6 +106,11 @@ struct MIDIfile * loadFile(const char * filename) | |||
106 | if(id == ID_MTRK) | 106 | if(id == ID_MTRK) |
107 | { | 107 | { |
108 | mfload->tracks[track] = readTrack(file); | 108 | mfload->tracks[track] = readTrack(file); |
109 | if (!mfload->tracks[track]) | ||
110 | { | ||
111 | rb->close(file); | ||
112 | return NULL; | ||
113 | } | ||
109 | track++; | 114 | track++; |
110 | } else | 115 | } else |
111 | { | 116 | { |
@@ -125,7 +130,7 @@ struct MIDIfile * loadFile(const char * filename) | |||
125 | * and then track 2 starts loading */ | 130 | * and then track 2 starts loading */ |
126 | 131 | ||
127 | int rStatus = 0; | 132 | int rStatus = 0; |
128 | /* Returns 0 if done, 1 if keep going */ | 133 | /* Returns 0 if done, 1 if keep going and -1 in case of error */ |
129 | static int readEvent(int file, void * dest) | 134 | static int readEvent(int file, void * dest) |
130 | { | 135 | { |
131 | struct Event dummy; | 136 | struct Event dummy; |
@@ -152,6 +157,8 @@ static int readEvent(int file, void * dest) | |||
152 | { | 157 | { |
153 | /* Null-terminate for text events */ | 158 | /* Null-terminate for text events */ |
154 | ev->evData = malloc(ev->len+1); /* Extra byte for the null termination */ | 159 | ev->evData = malloc(ev->len+1); /* Extra byte for the null termination */ |
160 | if (!ev->evData) | ||
161 | return -1; | ||
155 | 162 | ||
156 | rb->read(file, ev->evData, ev->len); | 163 | rb->read(file, ev->evData, ev->len); |
157 | ev->evData[ev->len] = 0; | 164 | ev->evData[ev->len] = 0; |
@@ -272,27 +279,35 @@ struct Track * readTrack(int file) | |||
272 | 279 | ||
273 | int pos = rb->lseek(file, 0, SEEK_CUR); | 280 | int pos = rb->lseek(file, 0, SEEK_CUR); |
274 | 281 | ||
275 | while(readEvent(file, NULL)) /* Memory saving technique */ | 282 | int evstat; |
283 | |||
284 | while ((evstat = readEvent(file, NULL)) > 0) /* Memory saving technique */ | ||
276 | numEvents++; /* Attempt to read in events, count how many */ | 285 | numEvents++; /* Attempt to read in events, count how many */ |
277 | /* THEN allocate memory and read them in */ | 286 | /* THEN allocate memory and read them in */ |
287 | if (evstat < 0) | ||
288 | return NULL; | ||
278 | rb->lseek(file, pos, SEEK_SET); | 289 | rb->lseek(file, pos, SEEK_SET); |
279 | 290 | ||
280 | int trackSize = (numEvents+1) * sizeof(struct Event); | 291 | int trackSize = (numEvents+1) * sizeof(struct Event); |
281 | void * dataPtr = malloc(trackSize); | 292 | void * dataPtr = malloc(trackSize); |
293 | if (!dataPtr) | ||
294 | return NULL; | ||
282 | trk->dataBlock = dataPtr; | 295 | trk->dataBlock = dataPtr; |
283 | 296 | ||
284 | numEvents=0; | 297 | numEvents=0; |
285 | 298 | ||
286 | while(readEvent(file, dataPtr)) | 299 | while ((evstat = readEvent(file, dataPtr)) > 0) |
287 | { | 300 | { |
288 | if(trackSize < dataPtr-trk->dataBlock) | 301 | if(trackSize < dataPtr-trk->dataBlock) |
289 | { | 302 | { |
290 | midi_debug("Track parser memory out of bounds"); | 303 | midi_debug("Track parser memory out of bounds"); |
291 | exit(1); | 304 | return NULL; |
292 | } | 305 | } |
293 | dataPtr+=sizeof(struct Event); | 306 | dataPtr+=sizeof(struct Event); |
294 | numEvents++; | 307 | numEvents++; |
295 | } | 308 | } |
309 | if (evstat < 0) | ||
310 | return NULL; | ||
296 | trk->numEvents = numEvents; | 311 | trk->numEvents = numEvents; |
297 | 312 | ||
298 | return trk; | 313 | return trk; |
diff --git a/apps/plugins/midi/midiplay.c b/apps/plugins/midi/midiplay.c index bef13b649d..8e867e5173 100644 --- a/apps/plugins/midi/midiplay.c +++ b/apps/plugins/midi/midiplay.c | |||
@@ -348,6 +348,10 @@ | |||
348 | #define SYNC | 348 | #define SYNC |
349 | #endif | 349 | #endif |
350 | 350 | ||
351 | #ifndef ALIGNED_ATTR | ||
352 | #define ALIGNED_ATTR(x) __attribute__((aligned(x))) | ||
353 | #endif | ||
354 | |||
351 | struct MIDIfile * mf IBSS_ATTR; | 355 | struct MIDIfile * mf IBSS_ATTR; |
352 | 356 | ||
353 | int number_of_samples IBSS_ATTR; /* the number of samples in the current tick */ | 357 | int number_of_samples IBSS_ATTR; /* the number of samples in the current tick */ |
@@ -355,52 +359,79 @@ int playing_time IBSS_ATTR; /* How many seconds into the file have we been play | |||
355 | int samples_this_second IBSS_ATTR; /* How many samples produced during this second so far? */ | 359 | int samples_this_second IBSS_ATTR; /* How many samples produced during this second so far? */ |
356 | long bpm IBSS_ATTR; | 360 | long bpm IBSS_ATTR; |
357 | 361 | ||
358 | int32_t gmbuf[BUF_SIZE*NBUF]; | 362 | #ifndef SYNC |
359 | static unsigned int samples_in_buf; | 363 | /* Small silence clip. ~5.80ms @ 44.1kHz */ |
364 | static int32_t silence[256] ALIGNED_ATTR(4) = { 0 }; | ||
365 | |||
366 | static int32_t gmbuf[BUF_SIZE * NBUF] ALIGNED_ATTR(4); | ||
367 | |||
368 | static volatile bool swap = false; | ||
369 | static volatile bool lastswap = true; | ||
370 | #else | ||
371 | static int32_t gmbuf[BUF_SIZE] ALIGNED_ATTR(4); | ||
372 | #endif | ||
373 | |||
374 | static volatile size_t samples_in_buf; | ||
360 | 375 | ||
361 | bool midi_end = false; | 376 | static volatile bool midi_end = false; |
362 | bool quit = false; | 377 | static volatile bool quit = false; |
363 | bool swap = false; | 378 | |
364 | bool lastswap = true; | 379 | static int32_t samp_buf[MAX_SAMPLES * 2] IBSS_ATTR; |
380 | |||
381 | static struct dsp_config *dsp; | ||
382 | static struct dsp_buffer src; | ||
383 | static struct dsp_buffer dst; | ||
365 | 384 | ||
366 | static inline void synthbuf(void) | 385 | static inline void synthbuf(void) |
367 | { | 386 | { |
368 | int32_t *outptr; | 387 | int32_t *outptr; |
369 | int i = BUF_SIZE; | 388 | int available = BUF_SIZE; |
370 | 389 | ||
371 | #if defined(HAVE_ADJUSTABLE_CPU_FREQ) | ||
372 | rb->cpu_boost(true); | ||
373 | #endif | ||
374 | #ifndef SYNC | 390 | #ifndef SYNC |
375 | if (lastswap == swap) | 391 | if (lastswap == swap) |
376 | return; | 392 | return; |
377 | lastswap = swap; | ||
378 | 393 | ||
379 | outptr = (swap ? gmbuf : gmbuf+BUF_SIZE); | 394 | outptr = (swap ? gmbuf : gmbuf+BUF_SIZE); |
380 | #else | 395 | #else |
381 | outptr = gmbuf; | 396 | outptr = gmbuf; |
382 | #endif | 397 | #endif |
383 | if (midi_end) { | ||
384 | samples_in_buf = 0; | ||
385 | return; | ||
386 | } | ||
387 | 398 | ||
399 | #if defined(HAVE_ADJUSTABLE_CPU_FREQ) | ||
400 | rb->cpu_boost(true); | ||
401 | #endif | ||
388 | /* synth samples for as many whole ticks as we can fit in the buffer */ | 402 | /* synth samples for as many whole ticks as we can fit in the buffer */ |
389 | for (; i >= number_of_samples; i -= number_of_samples) | 403 | while (available > 0) |
390 | { | 404 | { |
391 | synthSamples((int32_t*)outptr, number_of_samples); | 405 | if ((dst.remcount <= 0) && !midi_end) |
392 | outptr += number_of_samples; | 406 | { |
393 | #ifndef SYNC | 407 | int nsamples = synthSamples(samp_buf, number_of_samples); |
394 | /* synthbuf is called in interrupt context is SYNC is defined so it cannot yield | 408 | if (nsamples < number_of_samples) |
395 | that bug causing the sim to crach when not using SYNC should really be fixed */ | 409 | number_of_samples -= nsamples; |
396 | rb->yield(); | 410 | else if (!tick()) |
397 | #endif | 411 | midi_end = true; /* no more midi data to play */ |
398 | if (tick() == 0) | 412 | src.remcount = nsamples; |
399 | midi_end = true; /* no more midi data to play */ | 413 | src.pin[0] = &samp_buf[0]; |
414 | src.pin[1] = &samp_buf[1]; | ||
415 | src.proc_mask = 0; | ||
416 | } | ||
417 | dst.remcount = 0; | ||
418 | dst.bufcount = available; | ||
419 | dst.p16out = (int16_t *)outptr; | ||
420 | rb->dsp_process(dsp, &src, &dst); | ||
421 | if (dst.remcount > 0) | ||
422 | { | ||
423 | outptr += dst.remcount; | ||
424 | available -= dst.remcount; | ||
425 | } | ||
426 | else if (midi_end) | ||
427 | break; | ||
400 | } | 428 | } |
401 | 429 | ||
402 | /* how many samples did we write to the buffer? */ | 430 | /* how many samples did we write to the buffer? */ |
403 | samples_in_buf = BUF_SIZE-i; | 431 | samples_in_buf = BUF_SIZE - available; |
432 | #ifndef SYNC | ||
433 | lastswap = swap; | ||
434 | #endif | ||
404 | #if defined(HAVE_ADJUSTABLE_CPU_FREQ) | 435 | #if defined(HAVE_ADJUSTABLE_CPU_FREQ) |
405 | rb->cpu_boost(false); | 436 | rb->cpu_boost(false); |
406 | #endif | 437 | #endif |
@@ -409,26 +440,27 @@ static inline void synthbuf(void) | |||
409 | static void get_more(const void** start, size_t* size) | 440 | static void get_more(const void** start, size_t* size) |
410 | { | 441 | { |
411 | #ifndef SYNC | 442 | #ifndef SYNC |
412 | if(lastswap != swap) | 443 | swap = !swap; |
444 | if(lastswap == swap) | ||
413 | { | 445 | { |
414 | midi_debug("Buffer miss!"); /* Comment out the midi_debug to make missses less noticable. */ | 446 | *start = silence; |
447 | *size = sizeof(silence); | ||
448 | swap = !swap; | ||
449 | return; | ||
415 | } | 450 | } |
416 | 451 | else if (samples_in_buf) | |
452 | *start = swap ? (gmbuf + BUF_SIZE) : gmbuf; | ||
417 | #else | 453 | #else |
418 | synthbuf(); /* For some reason midiplayer crashes when an update is forced */ | 454 | synthbuf(); /* For some reason midiplayer crashes when an update is forced */ |
455 | if (samples_in_buf) | ||
456 | *start = gmbuf; | ||
419 | #endif | 457 | #endif |
420 | 458 | else | |
421 | *size = samples_in_buf*sizeof(int32_t); | 459 | { |
422 | #ifndef SYNC | ||
423 | *start = swap ? gmbuf : gmbuf + BUF_SIZE; | ||
424 | swap = !swap; | ||
425 | #else | ||
426 | *start = gmbuf; | ||
427 | #endif | ||
428 | if (samples_in_buf==0) { | ||
429 | *start = NULL; | 460 | *start = NULL; |
430 | quit = true; /* this was the last buffer to play */ | 461 | quit = true; /* this was the last buffer to play */ |
431 | } | 462 | } |
463 | *size = samples_in_buf*sizeof(int32_t); | ||
432 | } | 464 | } |
433 | 465 | ||
434 | static int midimain(const void * filename) | 466 | static int midimain(const void * filename) |
@@ -460,13 +492,26 @@ static int midimain(const void * filename) | |||
460 | return -1; | 492 | return -1; |
461 | } | 493 | } |
462 | 494 | ||
495 | rb->talk_force_shutup(); | ||
463 | rb->pcm_play_stop(); | 496 | rb->pcm_play_stop(); |
464 | #if INPUT_SRC_CAPS != 0 | 497 | #if INPUT_SRC_CAPS != 0 |
465 | /* Select playback */ | 498 | /* Select playback */ |
466 | rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); | 499 | rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); |
467 | rb->audio_set_output_source(AUDIO_SRC_PLAYBACK); | 500 | rb->audio_set_output_source(AUDIO_SRC_PLAYBACK); |
468 | #endif | 501 | #endif |
469 | rb->pcm_set_frequency(SAMPLE_RATE); /* 44100 22050 11025 */ | 502 | |
503 | dst.remcount = 0; | ||
504 | dsp = rb->dsp_get_config(CODEC_IDX_AUDIO); | ||
505 | rb->dsp_configure(dsp, DSP_RESET, 0); | ||
506 | rb->dsp_configure(dsp, DSP_FLUSH, 0); | ||
507 | rb->dsp_configure(dsp, DSP_SET_OUT_FREQUENCY, rb->mixer_get_frequency()); | ||
508 | #ifdef HAVE_PITCHCONTROL | ||
509 | rb->sound_set_pitch(PITCH_SPEED_100); | ||
510 | rb->dsp_set_timestretch(PITCH_SPEED_100); | ||
511 | #endif | ||
512 | rb->dsp_configure(dsp, DSP_SET_SAMPLE_DEPTH, 22); | ||
513 | rb->dsp_configure(dsp, DSP_SET_FREQUENCY, SAMPLE_RATE); /* 44100 22050 11025 */ | ||
514 | rb->dsp_configure(dsp, DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); | ||
470 | 515 | ||
471 | /* | 516 | /* |
472 | * tick() will do one MIDI clock tick. Then, there's a loop here that | 517 | * tick() will do one MIDI clock tick. Then, there's a loop here that |
@@ -501,8 +546,12 @@ static int midimain(const void * filename) | |||
501 | playing_time = 0; | 546 | playing_time = 0; |
502 | samples_this_second = 0; | 547 | samples_this_second = 0; |
503 | 548 | ||
549 | #ifndef SYNC | ||
504 | synthbuf(); | 550 | synthbuf(); |
505 | rb->pcm_play_data(&get_more, NULL, NULL, 0); | 551 | #endif |
552 | |||
553 | rb->pcmbuf_fade(false, true); | ||
554 | rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, get_more, NULL, 0); | ||
506 | 555 | ||
507 | while (!quit) | 556 | while (!quit) |
508 | { | 557 | { |
@@ -547,7 +596,9 @@ static int midimain(const void * filename) | |||
547 | { | 596 | { |
548 | /* Rewinding is tricky. Basically start the file over */ | 597 | /* Rewinding is tricky. Basically start the file over */ |
549 | /* but run through the tracks without the synth running */ | 598 | /* but run through the tracks without the synth running */ |
550 | rb->pcm_play_stop(); | 599 | rb->mixer_channel_stop(PCM_MIXER_CHAN_PLAYBACK); |
600 | rb->dsp_configure(dsp, DSP_FLUSH, 0); | ||
601 | dst.remcount = 0; | ||
551 | #if defined(HAVE_ADJUSTABLE_CPU_FREQ) | 602 | #if defined(HAVE_ADJUSTABLE_CPU_FREQ) |
552 | rb->cpu_boost(true); | 603 | rb->cpu_boost(true); |
553 | #endif | 604 | #endif |
@@ -555,39 +606,45 @@ static int midimain(const void * filename) | |||
555 | #if defined(HAVE_ADJUSTABLE_CPU_FREQ) | 606 | #if defined(HAVE_ADJUSTABLE_CPU_FREQ) |
556 | rb->cpu_boost(false); | 607 | rb->cpu_boost(false); |
557 | #endif | 608 | #endif |
609 | #ifndef SYNC | ||
558 | lastswap = !swap; | 610 | lastswap = !swap; |
559 | synthbuf(); | 611 | synthbuf(); |
612 | #endif | ||
560 | midi_debug("Rewind to %d:%02d\n", playing_time/60, playing_time%60); | 613 | midi_debug("Rewind to %d:%02d\n", playing_time/60, playing_time%60); |
561 | if (is_playing) | 614 | if (is_playing) |
562 | rb->pcm_play_data(&get_more, NULL, NULL, 0); | 615 | rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, get_more, NULL, 0); |
563 | break; | 616 | break; |
564 | } | 617 | } |
565 | 618 | ||
566 | case MIDI_FFWD: | 619 | case MIDI_FFWD: |
567 | { | 620 | { |
568 | rb->pcm_play_stop(); | 621 | rb->mixer_channel_stop(PCM_MIXER_CHAN_PLAYBACK); |
622 | rb->dsp_configure(dsp, DSP_FLUSH, 0); | ||
623 | dst.remcount = 0; | ||
624 | #if defined(HAVE_ADJUSTABLE_CPU_FREQ) | ||
625 | rb->cpu_boost(true); | ||
626 | #endif | ||
569 | seekForward(5); | 627 | seekForward(5); |
628 | #if defined(HAVE_ADJUSTABLE_CPU_FREQ) | ||
629 | rb->cpu_boost(false); | ||
630 | #endif | ||
631 | #ifndef SYNC | ||
570 | lastswap = !swap; | 632 | lastswap = !swap; |
571 | synthbuf(); | 633 | synthbuf(); |
634 | #endif | ||
572 | midi_debug("Skip to %d:%02d\n", playing_time/60, playing_time%60); | 635 | midi_debug("Skip to %d:%02d\n", playing_time/60, playing_time%60); |
573 | if (is_playing) | 636 | if (is_playing) |
574 | rb->pcm_play_data(&get_more, NULL, NULL, 0); | 637 | rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, get_more, NULL, 0); |
575 | break; | 638 | break; |
576 | } | 639 | } |
577 | 640 | ||
578 | case MIDI_PLAYPAUSE: | 641 | case MIDI_PLAYPAUSE: |
579 | { | 642 | { |
580 | if (is_playing) | 643 | is_playing = !is_playing; |
581 | { | 644 | midi_debug("%s %d:%02d\n", |
582 | midi_debug("Paused at %d:%02d\n", playing_time/60, playing_time%60); | 645 | is_playing ? "Playing from" : "Paused at", |
583 | is_playing = false; | 646 | playing_time/60, playing_time%60); |
584 | rb->pcm_play_stop(); | 647 | rb->mixer_channel_play_pause(PCM_MIXER_CHAN_PLAYBACK, is_playing); |
585 | } else | ||
586 | { | ||
587 | midi_debug("Playing from %d:%02d\n", playing_time/60, playing_time%60); | ||
588 | is_playing = true; | ||
589 | rb->pcm_play_data(&get_more, NULL, NULL, 0); | ||
590 | } | ||
591 | break; | 648 | break; |
592 | } | 649 | } |
593 | 650 | ||
@@ -598,6 +655,10 @@ static int midimain(const void * filename) | |||
598 | quit = true; | 655 | quit = true; |
599 | } | 656 | } |
600 | } | 657 | } |
658 | |||
659 | rb->pcmbuf_fade(false, false); | ||
660 | rb->mixer_channel_stop(PCM_MIXER_CHAN_PLAYBACK); | ||
661 | |||
601 | return 0; | 662 | return 0; |
602 | } | 663 | } |
603 | 664 | ||
@@ -625,9 +686,6 @@ enum plugin_status plugin_start(const void* parameter) | |||
625 | rb->profstop(); | 686 | rb->profstop(); |
626 | #endif | 687 | #endif |
627 | 688 | ||
628 | rb->pcm_play_stop(); | ||
629 | rb->pcm_set_frequency(HW_SAMPR_DEFAULT); | ||
630 | |||
631 | rb->splash(HZ, "FINISHED PLAYING"); | 689 | rb->splash(HZ, "FINISHED PLAYING"); |
632 | 690 | ||
633 | if (retval == -1) | 691 | if (retval == -1) |
diff --git a/apps/plugins/midi/midiutil.c b/apps/plugins/midi/midiutil.c index bfac1d5244..b9e57a405b 100644 --- a/apps/plugins/midi/midiutil.c +++ b/apps/plugins/midi/midiutil.c | |||
@@ -39,37 +39,40 @@ struct SynthObject voices[MAX_VOICES] IBSS_ATTR; | |||
39 | 39 | ||
40 | static void *alloc(int size) | 40 | static void *alloc(int size) |
41 | { | 41 | { |
42 | static char *offset = NULL; | 42 | static char *offset[2] = {NULL}; |
43 | static size_t totalSize = 0; | 43 | static size_t totalSize[2] = {0}; |
44 | char *ret; | 44 | char *ret; |
45 | int n; | ||
45 | 46 | ||
46 | int remainder = size % 4; | 47 | int remainder = size % 4; |
47 | 48 | ||
48 | size = size + 4-remainder; | 49 | size = size + 4-remainder; |
49 | 50 | ||
50 | if (offset == NULL) | 51 | if (offset[0] == NULL) |
51 | { | 52 | { |
52 | offset = rb->plugin_get_audio_buffer(&totalSize); | 53 | offset[0] = rb->plugin_get_buffer(&totalSize[0]); |
53 | } | 54 | } |
54 | 55 | ||
55 | if (size + 4 > (int)totalSize) | 56 | if (offset[1] == NULL) |
56 | { | 57 | { |
57 | midi_debug("Out of Memory"); | 58 | offset[1] = rb->plugin_get_audio_buffer(&totalSize[1]); |
58 | midi_debug("MALLOC BARF"); | 59 | } |
59 | midi_debug("MALLOC BARF"); | 60 | |
60 | midi_debug("MALLOC BARF"); | 61 | n = (totalSize[0] > totalSize[1]) ? 1 : 0; |
61 | midi_debug("MALLOC BARF"); | ||
62 | midi_debug("MALLOC BARF"); | ||
63 | /* We've made our point. */ | ||
64 | 62 | ||
63 | if (size + 4 > (int)totalSize[n]) | ||
64 | n ^= 1; | ||
65 | if (size + 4 > (int)totalSize[n]) | ||
66 | { | ||
67 | midi_debug("Out of Memory"); | ||
65 | return NULL; | 68 | return NULL; |
66 | } | 69 | } |
67 | 70 | ||
68 | ret = offset + 4; | 71 | ret = offset[n] + 4; |
69 | *((unsigned int *)offset) = size; | 72 | *((unsigned int *)offset[n]) = size; |
70 | 73 | ||
71 | offset += size + 4; | 74 | offset[n] += size + 4; |
72 | totalSize -= size + 4; | 75 | totalSize[n] -= size + 4; |
73 | return ret; | 76 | return ret; |
74 | } | 77 | } |
75 | 78 | ||
@@ -117,7 +120,8 @@ unsigned char readChar(int file) | |||
117 | void * readData(int file, int len) | 120 | void * readData(int file, int len) |
118 | { | 121 | { |
119 | void * dat = malloc(len); | 122 | void * dat = malloc(len); |
120 | rb->read(file, dat, len); | 123 | if (dat) |
124 | rb->read(file, dat, len); | ||
121 | return dat; | 125 | return dat; |
122 | } | 126 | } |
123 | 127 | ||
diff --git a/apps/plugins/midi/midiutil.h b/apps/plugins/midi/midiutil.h index cf3666c97f..72bff11b3f 100644 --- a/apps/plugins/midi/midiutil.h +++ b/apps/plugins/midi/midiutil.h | |||
@@ -25,14 +25,11 @@ | |||
25 | 25 | ||
26 | #define BUF_SIZE 16384 /* 64 kB output buffers */ | 26 | #define BUF_SIZE 16384 /* 64 kB output buffers */ |
27 | #define NBUF 2 | 27 | #define NBUF 2 |
28 | #define MAX_SAMPLES 512 | ||
28 | 29 | ||
29 | #ifndef SIMULATOR | 30 | #ifndef SIMULATOR |
30 | 31 | ||
31 | #if (HW_SAMPR_CAPS & SAMPR_CAP_22) /* use 22050Hz if we can */ | ||
32 | #define SAMPLE_RATE SAMPR_22 /* 22050 */ | ||
33 | #else | ||
34 | #define SAMPLE_RATE SAMPR_44 /* 44100 */ | 32 | #define SAMPLE_RATE SAMPR_44 /* 44100 */ |
35 | #endif | ||
36 | 33 | ||
37 | /* Some of the pp based targets can't handle too many voices | 34 | /* Some of the pp based targets can't handle too many voices |
38 | mainly because they have to use 44100Hz sample rate, this could be | 35 | mainly because they have to use 44100Hz sample rate, this could be |
diff --git a/apps/plugins/midi/synth.c b/apps/plugins/midi/synth.c index e95dd7cec9..f199d544e5 100644 --- a/apps/plugins/midi/synth.c +++ b/apps/plugins/midi/synth.c | |||
@@ -300,7 +300,8 @@ static inline void synthVoice(struct SynthObject * so, int32_t * out, unsigned i | |||
300 | s1 = so->decay; | 300 | s1 = so->decay; |
301 | s2 = s1 * pan; | 301 | s2 = s1 * pan; |
302 | s1 = (s1 << 7) -s2; | 302 | s1 = (s1 << 7) -s2; |
303 | *(out++) += ((s1 << 9) & 0xFFFF0000) | ((s2 >> 7) &0xFFFF); | 303 | *(out++) += s1; |
304 | *(out++) += s2; | ||
304 | continue; | 305 | continue; |
305 | } | 306 | } |
306 | } else /* OK to advance voice */ | 307 | } else /* OK to advance voice */ |
@@ -431,7 +432,8 @@ static inline void synthVoice(struct SynthObject * so, int32_t * out, unsigned i | |||
431 | 432 | ||
432 | s2 = s1 * pan; | 433 | s2 = s1 * pan; |
433 | s1 = (s1 << 7) - s2; | 434 | s1 = (s1 << 7) - s2; |
434 | *(out++) += ((s1 << 9) & 0xFFFF0000) | ((s2 >> 7) &0xFFFF); | 435 | *(out++) += s1; |
436 | *(out++) += s2; | ||
435 | } | 437 | } |
436 | 438 | ||
437 | /* store these again */ | 439 | /* store these again */ |
@@ -441,40 +443,29 @@ static inline void synthVoice(struct SynthObject * so, int32_t * out, unsigned i | |||
441 | return; | 443 | return; |
442 | } | 444 | } |
443 | 445 | ||
444 | /* buffer to hold all the samples for the current tick, this is a hack | ||
445 | neccesary for coldfire targets as pcm_play_data uses the dma which cannot | ||
446 | access iram */ | ||
447 | int32_t samp_buf[512] IBSS_ATTR; | ||
448 | |||
449 | /* synth num_samples samples and write them to the */ | 446 | /* synth num_samples samples and write them to the */ |
450 | /* buffer pointed to by buf_ptr */ | 447 | /* buffer pointed to by buf_ptr */ |
451 | void synthSamples(int32_t *buf_ptr, unsigned int num_samples) ICODE_ATTR; | 448 | size_t synthSamples(int32_t *buf_ptr, size_t num_samples) ICODE_ATTR; |
452 | void synthSamples(int32_t *buf_ptr, unsigned int num_samples) | 449 | size_t synthSamples(int32_t *buf_ptr, size_t num_samples) |
453 | { | 450 | { |
454 | if (UNLIKELY(num_samples > 512)) | 451 | unsigned int i; |
455 | DEBUGF("num_samples is too big!\n"); | 452 | struct SynthObject *voicept; |
456 | else | 453 | size_t nsamples = MIN(num_samples, MAX_SAMPLES); |
457 | { | ||
458 | int i; | ||
459 | struct SynthObject *voicept; | ||
460 | 454 | ||
461 | rb->memset(samp_buf, 0, num_samples*4); | 455 | rb->memset(buf_ptr, 0, nsamples * 2 * sizeof(int32_t)); |
462 | 456 | ||
463 | for(i=0; i < MAX_VOICES; i++) | 457 | for(i=0; i < MAX_VOICES; i++) |
458 | { | ||
459 | voicept=&voices[i]; | ||
460 | if(voicept->isUsed) | ||
464 | { | 461 | { |
465 | voicept=&voices[i]; | 462 | synthVoice(voicept, buf_ptr, nsamples); |
466 | if(voicept->isUsed) | ||
467 | { | ||
468 | synthVoice(voicept, samp_buf, num_samples); | ||
469 | } | ||
470 | } | 463 | } |
471 | |||
472 | rb->memcpy(buf_ptr, samp_buf, num_samples*4); | ||
473 | } | 464 | } |
474 | 465 | ||
475 | /* TODO: Automatic Gain Control, anyone? */ | 466 | /* TODO: Automatic Gain Control, anyone? */ |
476 | /* Or, should this be implemented on the DSP's output volume instead? */ | 467 | /* Or, should this be implemented on the DSP's output volume instead? */ |
477 | 468 | ||
478 | return; /* No more ghetto lowpass filter. Linear interpolation works well. */ | 469 | return nsamples; /* No more ghetto lowpass filter. Linear interpolation works well. */ |
479 | } | 470 | } |
480 | 471 | ||
diff --git a/apps/plugins/midi/synth.h b/apps/plugins/midi/synth.h index 4cc6a545f0..b44da21fd2 100644 --- a/apps/plugins/midi/synth.h +++ b/apps/plugins/midi/synth.h | |||
@@ -20,7 +20,7 @@ | |||
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig); | 21 | int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig); |
22 | void setPoint(struct SynthObject * so, int pt); | 22 | void setPoint(struct SynthObject * so, int pt); |
23 | void synthSamples(int32_t *buf_ptr, unsigned int num_samples); | 23 | size_t synthSamples(int32_t *buf_ptr, size_t num_samples); |
24 | 24 | ||
25 | void resetControllers(void); | 25 | void resetControllers(void); |
26 | 26 | ||