diff --git a/apps/plugins/midi/midiplay.c b/apps/plugins/midi/midiplay.c index ac23187686..b0024087b6 100644 --- a/apps/plugins/midi/midiplay.c +++ b/apps/plugins/midi/midiplay.c @@ -29,24 +29,7 @@ PLUGIN_HEADER PLUGIN_IRAM_DECLARE /* variable button definitions */ -#if CONFIG_KEYPAD == RECORDER_PAD -#define BTN_QUIT BUTTON_OFF -#define BTN_RIGHT BUTTON_RIGHT -#define BTN_UP BUTTON_UP -#define BTN_DOWN BUTTON_DOWN -#define BTN_LEFT BUTTON_LEFT -#define BTN_PLAY BUTTON_PLAY - -#elif CONFIG_KEYPAD == ONDIO_PAD -#define BTN_QUIT BUTTON_OFF -#define BTN_RIGHT BUTTON_RIGHT -#define BTN_UP BUTTON_UP -#define BTN_DOWN BUTTON_DOWN -#define BTN_LEFT BUTTON_LEFT -#define BTN_PLAY (BUTTON_MENU | BUTTON_OFF) - - -#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) +#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) #define BTN_QUIT BUTTON_OFF #define BTN_RIGHT BUTTON_RIGHT #define BTN_UP BUTTON_UP @@ -209,27 +192,223 @@ PLUGIN_IRAM_DECLARE struct MIDIfile * mf IBSS_ATTR; -int numberOfSamples IBSS_ATTR; /* the number of samples in the current tick */ -int playingTime IBSS_ATTR; /* How many seconds into the file have we been playing? */ -int samplesThisSecond IBSS_ATTR; /* How many samples produced during this second so far? */ - +int number_of_samples IBSS_ATTR; /* the number of samples in the current tick */ +int playing_time IBSS_ATTR; /* How many seconds into the file have we been playing? */ +int samples_this_second IBSS_ATTR; /* How many samples produced during this second so far? */ long bpm IBSS_ATTR; int32_t gmbuf[BUF_SIZE*NBUF]; static unsigned int samples_in_buf; -int quit=0; +bool quit = false; +bool swap = false; +bool lastswap = true; -static int midimain(const void * filename); +static inline void synthbuf(void) +{ + int32_t *outptr; + int i = BUF_SIZE; + +#ifndef SYNC + if (lastswap == swap) + return; + lastswap = swap; + + outptr = (swap ? gmbuf : gmbuf+BUF_SIZE); +#else + outptr = gmbuf; +#endif + + /* synth samples for as many whole ticks as we can fit in the buffer */ + for (; i >= number_of_samples; i -= number_of_samples) + { + synthSamples((int32_t*)outptr, number_of_samples); + outptr += number_of_samples; +#ifndef SYNC + /* synthbuf is called in interrupt context is SYNC is defined so it cannot yield + that bug causing the sim to crach when not using SYNC should really be fixed */ + rb->yield(); +#endif + if (tick() == 0) + quit = true; + } + + /* how many samples did we write to the buffer? */ + samples_in_buf = BUF_SIZE-i; +} + +void get_more(unsigned char** start, size_t* size) +{ +#ifndef SYNC + if(lastswap != swap) + { + printf("Buffer miss!"); /* Comment out the printf to make missses less noticable. */ + } + +#else + synthbuf(); /* For some reason midiplayer crashes when an update is forced */ +#endif + + *size = samples_in_buf*sizeof(int32_t); +#ifndef SYNC + *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE)); + swap = !swap; +#else + *start = (unsigned char*)(gmbuf); +#endif +} + +static int midimain(const void * filename) +{ + int a, notes_used, vol; + bool is_playing = true; /* false = paused */ + + printf("Loading file"); + mf = loadFile(filename); + + if (mf == NULL) + { + printf("Error loading file."); + return -1; + } + + if (initSynth(mf, ROCKBOX_DIR "/patchset/patchset.cfg", + ROCKBOX_DIR "/patchset/drums.cfg") == -1) + return -1; + + rb->pcm_play_stop(); +#if INPUT_SRC_CAPS != 0 + /* Select playback */ + rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); + rb->audio_set_output_source(AUDIO_SRC_PLAYBACK); +#endif + rb->pcm_set_frequency(SAMPLE_RATE); /* 44100 22050 11025 */ + + /* + * tick() will do one MIDI clock tick. Then, there's a loop here that + * will generate the right number of samples per MIDI tick. The whole + * MIDI playback is timed in terms of this value.. there are no forced + * delays or anything. It just produces enough samples for each tick, and + * the playback of these samples is what makes the timings right. + * + * This seems to work quite well. On a laptop, anyway. + */ + + printf("Okay, starting sequencing"); + + bpm = mf->div*1000000/tempo; + number_of_samples = SAMPLE_RATE/bpm; + + /* Skip over any junk in the beginning of the file, so start playing */ + /* after the first note event */ + do + { + notes_used = 0; + for (a = 0; a < MAX_VOICES; a++) + if (voices[a].isUsed) + notes_used++; + tick(); + } while (notes_used == 0); + + playing_time = 0; + samples_this_second = 0; + + synthbuf(); + rb->pcm_play_data(&get_more, NULL, 0); + + while (!quit) + { + #ifndef SYNC + synthbuf(); + #endif + rb->yield(); + + /* Prevent idle poweroff */ + rb->reset_poweroff_timer(); + + /* Code taken from Oscilloscope plugin */ + switch (rb->button_get(false)) + { + case BTN_UP: + case BTN_UP | BUTTON_REPEAT: + { + vol = rb->global_settings->volume; + if (vol < rb->sound_max(SOUND_VOLUME)) + { + vol++; + rb->sound_set(SOUND_VOLUME, vol); + rb->global_settings->volume = vol; + } + break; + } + + case BTN_DOWN: + case BTN_DOWN | BUTTON_REPEAT: + { + vol = rb->global_settings->volume; + if (vol > rb->sound_min(SOUND_VOLUME)) + { + vol--; + rb->sound_set(SOUND_VOLUME, vol); + rb->global_settings->volume = vol; + } + break; + } + + case BTN_LEFT: + { + /* Rewinding is tricky. Basically start the file over */ + /* but run through the tracks without the synth running */ + rb->pcm_play_stop(); + seekBackward(5); + printf("Rewind to %d:%02d\n", playing_time/60, playing_time%60); + if (is_playing) + rb->pcm_play_data(&get_more, NULL, 0); + break; + } + + case BTN_RIGHT: + { + rb->pcm_play_stop(); + seekForward(5); + printf("Skip to %d:%02d\n", playing_time/60, playing_time%60); + if (is_playing) + rb->pcm_play_data(&get_more, NULL, 0); + break; + } + + case BTN_PLAY: + { + if (is_playing) + { + printf("Paused at %d:%02d\n", playing_time/60, playing_time%60); + is_playing = false; + rb->pcm_play_stop(); + } else + { + printf("Playing from %d:%02d\n", playing_time/60, playing_time%60); + is_playing = true; + rb->pcm_play_data(&get_more, NULL, 0); + } + break; + } + +#ifdef BTN_RC_QUIT + case BTN_RC_QUIT: +#endif + case BTN_QUIT: + quit = true; + } + } + return 0; +} enum plugin_status plugin_start(const void* parameter) { - int retval = 0; - - + int retval; PLUGIN_IRAM_INIT(rb) - if(parameter == NULL) + if (parameter == NULL) { rb->splash(HZ*2, " Play .MID file "); return PLUGIN_OK; @@ -261,210 +440,8 @@ enum plugin_status plugin_start(const void* parameter) #endif rb->splash(HZ, "FINISHED PLAYING"); - if(retval == -1) + if (retval == -1) return PLUGIN_ERROR; return PLUGIN_OK; } -bool swap=0; -bool lastswap=1; - -static inline void synthbuf(void) -{ - int32_t *outptr; - int i=BUF_SIZE; - -#ifndef SYNC - if(lastswap==swap) return; - lastswap=swap; - - outptr=(swap ? gmbuf : gmbuf+BUF_SIZE); -#else - outptr=gmbuf; -#endif - - /* synth samples for as many whole ticks as we can fit in the buffer */ - for(; i >= numberOfSamples; i -= numberOfSamples) - { - synthSamples((int32_t*)outptr, numberOfSamples); - outptr += numberOfSamples; - if( tick() == 0 ) - quit=1; - } - - /* how many samples did we write to the buffer? */ - samples_in_buf = BUF_SIZE-i; - -} - -void get_more(unsigned char** start, size_t* size) -{ -#ifndef SYNC - if(lastswap!=swap) - { - printf("Buffer miss!"); // Comment out the printf to make missses less noticable. - } - -#else - synthbuf(); // For some reason midiplayer crashes when an update is forced -#endif - - *size = samples_in_buf*sizeof(int32_t); -#ifndef SYNC - *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE)); - swap=!swap; -#else - *start = (unsigned char*)(gmbuf); -#endif -} - -static int midimain(const void * filename) -{ - int notesUsed = 0; - int a=0; - printf("Loading file"); - mf= loadFile(filename); - - if(mf == NULL) - { - printf("Error loading file."); - return -1; - } - - if (initSynth(mf, ROCKBOX_DIR "/patchset/patchset.cfg", - ROCKBOX_DIR "/patchset/drums.cfg") == -1) - return -1; - - rb->pcm_play_stop(); -#if INPUT_SRC_CAPS != 0 - /* Select playback */ - rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); - rb->audio_set_output_source(AUDIO_SRC_PLAYBACK); -#endif - rb->pcm_set_frequency(SAMPLE_RATE); // 44100 22050 11025 - - /* - * tick() will do one MIDI clock tick. Then, there's a loop here that - * will generate the right number of samples per MIDI tick. The whole - * MIDI playback is timed in terms of this value.. there are no forced - * delays or anything. It just produces enough samples for each tick, and - * the playback of these samples is what makes the timings right. - * - * This seems to work quite well. On a laptop, anyway. - */ - - printf("Okay, starting sequencing"); - - bpm=mf->div*1000000/tempo; - numberOfSamples=SAMPLE_RATE/bpm; - - - - /* Skip over any junk in the beginning of the file, so start playing */ - /* after the first note event */ - do - { - notesUsed = 0; - for(a=0; apcm_play_data(&get_more, NULL, 0); - - int isPlaying = 1; /* 0 = paused */ - int vol=0; - - while(!quit) - { - #ifndef SYNC - synthbuf(); - #endif - rb->yield(); - - /* Prevent idle poweroff */ - rb->reset_poweroff_timer(); - - /* Code taken from Oscilloscope plugin */ - switch(rb->button_get(false)) - { - case BTN_UP: - case BTN_UP | BUTTON_REPEAT: - vol = rb->global_settings->volume; - if (vol < rb->sound_max(SOUND_VOLUME)) - { - vol++; - rb->sound_set(SOUND_VOLUME, vol); - rb->global_settings->volume = vol; - } - break; - - case BTN_DOWN: - case BTN_DOWN | BUTTON_REPEAT: - vol = rb->global_settings->volume; - if (vol > rb->sound_min(SOUND_VOLUME)) - { - vol--; - rb->sound_set(SOUND_VOLUME, vol); - rb->global_settings->volume = vol; - } - break; - - - case BTN_LEFT: - { - /* Rewinding is tricky. Basically start the file over */ - /* but run through the tracks without the synth running */ - rb->pcm_play_stop(); - seekBackward(5); - printf("Rewind to %d:%02d\n", playingTime/60, playingTime%60); - - if(isPlaying) - rb->pcm_play_data(&get_more, NULL, 0); - break; - } - - case BTN_RIGHT: - { - rb->pcm_play_stop(); - seekForward(5); - printf("Skip to %d:%02d\n", playingTime/60, playingTime%60); - - if(isPlaying) - rb->pcm_play_data(&get_more, NULL, 0); - break; - } - - case BTN_PLAY: - { - if(isPlaying == 1) - { - printf("Paused at %d:%02d\n", playingTime/60, playingTime%60); - isPlaying = 0; - rb->pcm_play_stop(); - } else - { - printf("Playing from %d:%02d\n", playingTime/60, playingTime%60); - isPlaying = 1; - rb->pcm_play_data(&get_more, NULL, 0); - } - break; - } - -#ifdef BTN_RC_QUIT - case BTN_RC_QUIT: -#endif - case BTN_QUIT: - quit=1; - } - - - } - - return 0; -} diff --git a/apps/plugins/midi/midiutil.h b/apps/plugins/midi/midiutil.h index 4b1afa2928..ba64a00e28 100644 --- a/apps/plugins/midi/midiutil.h +++ b/apps/plugins/midi/midiutil.h @@ -32,8 +32,10 @@ #define SAMPLE_RATE SAMPR_44 /* 44100 */ #endif -#ifdef CPU_PP /* the pp based targets can't handle too many voices - mainly because they have to use 44100Hz sample rate */ +/* Some of the pp based targets can't handle too many voices + mainly because they have to use 44100Hz sample rate, this could be + improved to increase MAX_VOICES for targets that can do 22kHz */ +#ifdef CPU_PP #define MAX_VOICES 16 #else #define MAX_VOICES 24 /* Note: 24 midi channels is the minimum general midi spec implementation */ @@ -166,6 +168,8 @@ extern struct GPatch * drumSet[128]; extern struct MIDIfile * mf; -extern int numberOfSamples; +extern int number_of_samples; +extern int playing_time IBSS_ATTR; +extern int samples_this_second IBSS_ATTR; extern long bpm; diff --git a/apps/plugins/midi/sequencer.c b/apps/plugins/midi/sequencer.c index 11dd0e3f96..f97cac0130 100644 --- a/apps/plugins/midi/sequencer.c +++ b/apps/plugins/midi/sequencer.c @@ -23,10 +23,7 @@ #include "guspat.h" #include "synth.h" -extern int playingTime IBSS_ATTR; -extern int samplesThisSecond IBSS_ATTR; - -long tempo=375000; +long tempo = 375000; /* From the old patch config.... each patch is scaled. * Should be moved into patchset.cfg @@ -62,13 +59,13 @@ static inline void setVolScale(int a) static inline void setVol(int ch, int vol) { - int a=0; - chVol[ch]=vol; + int a; + chVol[ch] = vol; /* If channel volume changes, we need to recalculate the volume scale */ /* factor for all voices active on this channel */ - for(a=0; awaveforms[patchSet[chPat[ch]]->noteTable[note]]; - so->wf=wf; + struct GWaveform * wf = + patchSet[chPat[ch]]->waveforms[patchSet[chPat[ch]]->noteTable[note]]; + so->wf = wf; /* Used to be unsigned int, but math had to be done in different order to avoid overflow */ - unsigned long long delta= 0; + unsigned long long delta = 0; /* Old formula: @@ -169,10 +165,10 @@ static void findDelta(struct SynthObject * so, int ch, int note) static inline void computeDeltas(int ch) { - int a=0; - for(a = 0; awaveforms[0]; - voices[a].wf=wf; + voices[a].wf = wf; voices[a].delta = (((gustable[note]<rootFreq) * wf->sampRate / SAMPLE_RATE); - if(wf->mode & 28) + if (wf->mode & 28) // printf("\nWoah, a drum patch has a loop. Stripping the loop..."); wf->mode = wf->mode & (255-28); /* Turn it on */ - voices[a].isUsed=true; + voices[a].isUsed = true; setPoint(&voices[a], 0); } else @@ -284,16 +280,15 @@ inline void pressNote(int ch, int note, int vol) static void releaseNote(int ch, int note) { - - if(ch==9) + if (ch == 9) return; - int a=0; - for(a=0; amode & 28)) + if (voices[a].wf->mode & 28) { setPoint(&voices[a], 3); } @@ -306,10 +301,10 @@ static void sendEvent(struct Event * ev) const unsigned char status_low = ev->status & 0x0F; const unsigned char d1 = ev->d1; const unsigned char d2 = ev->d2; - switch(ev->status & 0xF0) + switch (ev->status & 0xF0) { case MIDI_CONTROL: - switch(d1) + switch (d1) { case CTRL_VOLUME: { @@ -318,7 +313,7 @@ static void sendEvent(struct Event * ev) } case CTRL_PANNING: { - chPan[status_low]=d2; + chPan[status_low] = d2; return; } case CTRL_DATAENT_MSB: @@ -365,7 +360,7 @@ static void sendEvent(struct Event * ev) return; case MIDI_NOTE_ON: - switch(d2) + switch (d2) { case 0: /* Release by vol=0 */ releaseNote(status_low, d1); @@ -381,139 +376,131 @@ static void sendEvent(struct Event * ev) return; case MIDI_PRGM: - if((status_low) != 9) + if (status_low != 9) setPatch(status_low, d1); } } void rewindFile(void) { - int i=0; - for(i=0; inumTracks; i++) + int i; + for (i = 0; i < mf->numTracks; i++) { mf->tracks[i]->delta = 0; mf->tracks[i]->pos = 0; } } - int tick(void) ICODE_ATTR; - -void seekBackward(int nsec) -{ - int notesUsed = 0, a=0; - int desiredTime = playingTime - nsec; /* Rewind 5 sec */ - - if(desiredTime < 0) - desiredTime = 0; - - /* Set controllers to default values */ - resetControllers(); - - /* Set the tempo to defalt */ - bpm=mf->div*1000000/tempo; - numberOfSamples=SAMPLE_RATE/bpm; - - - /* Reset the tracks to start */ - rewindFile(); - - /* Reset the time counter to 0 */ - playingTime = 0; - samplesThisSecond = 0; - - /* Quickly run through any initial things that occur before notes */ - do - { - notesUsed = 0; - for(a=0; anumTracks; a++) + int a, tracksAdv=0; + for (a = 0; a < mf->numTracks; a++) { struct Track * tr = mf->tracks[a]; - if(tr == NULL) + if (tr == NULL) printf("NULL TRACK: %d", a); - //BIG DEBUG STATEMENT //printf("\nTrack %2d, Event = %4d of %4d, Delta = %5d, Next = %4d", a, tr->pos, tr->numEvents, tr->delta, getEvent(tr, tr->pos)->delta); - - if(tr != NULL && (tr->pos < tr->numEvents)) + if (tr != NULL && (tr->pos < tr->numEvents)) { tr->delta++; tracksAdv++; - while(getEvent(tr, tr->pos)->delta <= tr->delta) + while (getEvent(tr, tr->pos)->delta <= tr->delta) { struct Event * e = getEvent(tr, tr->pos); - if(e->status != 0xFF) + if (e->status != 0xFF) { sendEvent(e); - if(((e->status&0xF0) == MIDI_PRGM)) + if ((e->status&0xF0) == MIDI_PRGM) { /* printf("\nPatch Event, patch[%d] ==> %d", e->status&0xF, e->d1); */ } } else { - if(e->d1 == 0x51) + if (e->d1 == 0x51) { tempo = (((short)e->evData[0])<<16)|(((short)e->evData[1])<<8)|(e->evData[2]); /* printf("\nMeta-Event: Tempo Set = %d", tempo); */ bpm=mf->div*1000000/tempo; - numberOfSamples=SAMPLE_RATE/bpm; + number_of_samples=SAMPLE_RATE/bpm; } } tr->delta = 0; tr->pos++; - if(tr->pos>=(tr->numEvents-1)) + if (tr->pos >= (tr->numEvents-1)) break; } } } - samplesThisSecond += numberOfSamples; + samples_this_second += number_of_samples; - while(samplesThisSecond >= SAMPLE_RATE) + while (samples_this_second >= SAMPLE_RATE) { - samplesThisSecond -= SAMPLE_RATE; - playingTime++; -// printf("Time: %d sec\n", playingTime); + samples_this_second -= SAMPLE_RATE; + playing_time++; } - if(tracksAdv != 0) + if (tracksAdv != 0) return 1; else return 0; } +void seekBackward(int nsec) +{ + int notes_used, a; + int desired_time = playing_time - nsec; /* Rewind 5 sec */ + + if (desired_time < 0) + desired_time = 0; + + /* Set controllers to default values */ + resetControllers(); + + /* Set the tempo to defalt */ + bpm = mf->div*1000000/tempo; + number_of_samples = SAMPLE_RATE/bpm; + + /* Reset the tracks to start */ + rewindFile(); + + /* Reset the time counter to 0 */ + playing_time = 0; + samples_this_second = 0; + + /* Quickly run through any initial things that occur before notes */ + do + { + notes_used = 0; + for (a = 0; a < MAX_VOICES; a++) + if (voices[a].isUsed) + notes_used++; + tick(); + } while (notes_used == 0); + + /* Reset the time counter to 0 */ + playing_time = 0; + samples_this_second = 0; + + /* Tick until goal is reached */ + while (playing_time < desired_time) + tick(); +} + +void seekForward(int nsec) +{ + int desired_time = playing_time + nsec; + while (tick() && playing_time < desired_time); +} +