From b2f1b5dd183b1171c81796946c868f2df8df9647 Mon Sep 17 00:00:00 2001 From: Stepan Moskovchenko Date: Mon, 1 May 2006 23:22:59 +0000 Subject: ---------------------------------------------------------------------- Added Karl Kurbjun's sound output patch, cleaned up some output. Main file is now midiplay.c, midi2wav is still in there for anyone who wants it. Set sampling rate to 22k, and increased note decay time. Reduced number of concurrent active voices and made new notes replace used voices if none are available. This makes lag less apparent. I really hope this wont go red. (turns around and runs) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9858 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/SOURCES | 2 +- apps/plugins/midi/guspat.c | 14 +-- apps/plugins/midi/midifile.c | 40 ++++---- apps/plugins/midi/midiutil.c | 48 +++++++--- apps/plugins/midi/sequencer.c | 109 +++++++++++++++------ apps/plugins/midi/synth.c | 83 ++++++++-------- apps/plugins/midiplay.c | 217 ++++++++++++++++++++++++++++++++++++++++++ apps/plugins/viewers.config | 2 +- 8 files changed, 400 insertions(+), 115 deletions(-) create mode 100644 apps/plugins/midiplay.c (limited to 'apps') diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index 1f64e9140b..edcbe3e53b 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES @@ -99,7 +99,7 @@ nim.c #if CONFIG_CODEC == SWCODEC /* software codec platforms */ mp3_encoder.c -midi2wav.c +midiplay.c wav2wv.c #else /* hardware codec platforms */ #ifndef HAVE_MMC /* not for Ondio, has no remote control pin */ diff --git a/apps/plugins/midi/guspat.c b/apps/plugins/midi/guspat.c index 6f1866cd58..4b5e7a6a28 100644 --- a/apps/plugins/midi/guspat.c +++ b/apps/plugins/midi/guspat.c @@ -31,11 +31,11 @@ unsigned int readDWord(int file) struct GWaveform * loadWaveform(int file) { - struct GWaveform * wav = (struct GWaveform *)allocate(sizeof(struct GWaveform)); + struct GWaveform * wav = (struct GWaveform *)malloc(sizeof(struct GWaveform)); rb->memset(wav, 0, sizeof(struct GWaveform)); wav->name=readData(file, 7); - printf("\nWAVE NAME = [%s]", wav->name); +/* printf("\nWAVE NAME = [%s]", wav->name); */ wav->fractions=readChar(file); wav->wavSize=readDWord(file); wav->startLoop=readDWord(file); @@ -62,7 +62,7 @@ struct GWaveform * loadWaveform(int file) wav->scaleFreq=readWord(file); wav->scaleFactor=readWord(file); - printf("\nScaleFreq = %d ScaleFactor = %d RootFreq = %d", wav->scaleFreq, wav->scaleFactor, wav->rootFreq); +/* printf("\nScaleFreq = %d ScaleFactor = %d RootFreq = %d", wav->scaleFreq, wav->scaleFactor, wav->rootFreq); */ wav->res=readData(file, 36); wav->data=readData(file, wav->wavSize); @@ -137,7 +137,7 @@ int selectWaveform(struct GPatch * pat, int midiNote) struct GPatch * gusload(char * filename) { - struct GPatch * gp = (struct GPatch *)allocate(sizeof(struct GPatch)); + struct GPatch * gp = (struct GPatch *)malloc(sizeof(struct GPatch)); rb->memset(gp, 0, sizeof(struct GPatch)); int file = rb->open(filename, O_RDONLY); @@ -175,15 +175,15 @@ struct GPatch * gusload(char * filename) gp->layerRes=readData(file,40); - printf("\nFILE: %s", filename); - printf("\nlayerSamples=%d", gp->numWaves); +/* printf("\nFILE: %s", filename); */ +/* printf("\nlayerSamples=%d", gp->numWaves); */ int a=0; for(a=0; anumWaves; a++) gp->waveforms[a] = loadWaveform(file); - printf("\nPrecomputing note table"); +/* printf("\nPrecomputing note table"); */ for(a=0; a<128; a++) { diff --git a/apps/plugins/midi/midifile.c b/apps/plugins/midi/midifile.c index 412cc6104d..61168f9d39 100644 --- a/apps/plugins/midi/midifile.c +++ b/apps/plugins/midi/midifile.c @@ -26,7 +26,7 @@ void bail(const char *); struct MIDIfile * loadFile(char * filename) { - struct MIDIfile * mf; + struct MIDIfile * mfload; int file = rb->open (filename, O_RDONLY); if(file==-1) @@ -34,15 +34,15 @@ struct MIDIfile * loadFile(char * filename) bail("Could not open file\n"); } - mf = (struct MIDIfile*)allocate(sizeof(struct MIDIfile)); + mfload = (struct MIDIfile*)malloc(sizeof(struct MIDIfile)); - if(mf==NULL) + if(mfload==NULL) { rb->close(file); bail("Could not allocate memory for MIDIfile struct\n"); } - rb->memset(mf, 0, sizeof(struct MIDIfile)); + rb->memset(mfload, 0, sizeof(struct MIDIfile)); if(readID(file) != ID_MTHD) { @@ -62,32 +62,32 @@ struct MIDIfile * loadFile(char * filename) bail("MIDI file type not supported"); } - mf->numTracks = readTwoBytes(file); - mf->div = readTwoBytes(file); + mfload->numTracks = readTwoBytes(file); + mfload->div = readTwoBytes(file); int track=0; - printf("\nnumTracks=%d div=%d\nBegin reading track data\n", mf->numTracks, mf->div); + printf("\nnumTracks=%d div=%d\nBegin reading track data\n", mfload->numTracks, mfload->div); - while(! eof(file) && track < mf->numTracks) + while(! eof(file) && track < mfload->numTracks) { unsigned char id = readID(file); if(id == ID_EOF) { - if(mf->numTracks != track) + if(mfload->numTracks != track) { - printf("\nError: file claims to have %d tracks.\n I only see %d here.\n", mf->numTracks, track); - mf->numTracks = track; + printf("\nError: file claims to have %d tracks.\n I only see %d here.\n", mfload->numTracks, track); + mfload->numTracks = track; } - return mf; + return mfload; } if(id == ID_MTRK) { - mf->tracks[track] = readTrack(file); + mfload->tracks[track] = readTrack(file); //exit(0); track++; } else @@ -98,16 +98,16 @@ struct MIDIfile * loadFile(char * filename) readChar(file); } } - return mf; + return mfload; } -int rStatus = 0; - /* Returns 0 if done, 1 if keep going */ int readEvent(int file, void * dest) { + + static int rStatus = 0; struct Event dummy; struct Event * ev = (struct Event *) dest; @@ -131,7 +131,7 @@ int readEvent(int file, void * dest) if(dest != NULL) { ev->evData = readData(file, ev->len); - printf("\nDATA: <%s>", ev->evData); +/* printf("\nDATA: <%s>", ev->evData); */ } else { @@ -173,11 +173,9 @@ int readEvent(int file, void * dest) return 1; } - - struct Track * readTrack(int file) { - struct Track * trk = (struct Track *)allocate(sizeof(struct Track)); + struct Track * trk = (struct Track *)malloc(sizeof(struct Track)); rb->memset(trk, 0, sizeof(struct Track)); trk->size = readFourBytes(file); @@ -194,7 +192,7 @@ struct Track * readTrack(int file) rb->lseek(file, pos, SEEK_SET); int trackSize = (numEvents+1) * sizeof(struct Event); - void * dataPtr = allocate(trackSize); + void * dataPtr = malloc(trackSize); trk->dataBlock = dataPtr; numEvents=0; diff --git a/apps/plugins/midi/midiutil.c b/apps/plugins/midi/midiutil.c index d0b968e52c..8e27e739e7 100644 --- a/apps/plugins/midi/midiutil.c +++ b/apps/plugins/midi/midiutil.c @@ -63,11 +63,11 @@ extern struct plugin_api * rb; -int chVol[16] IDATA_ATTR; /* Channel volume */ -int chPanLeft[16] IDATA_ATTR; /* Channel panning */ -int chPanRight[16] IDATA_ATTR; -int chPat[16]; /* Channel patch */ -int chPW[16]; /* Channel pitch wheel, MSB only */ +int chVol[16] IBSS_ATTR; /* Channel volume */ +int chPanLeft[16] IBSS_ATTR; /* Channel panning */ +int chPanRight[16] IBSS_ATTR; +int chPat[16] IBSS_ATTR; /* Channel patch */ +int chPW[16] IBSS_ATTR; /* Channel pitch wheel, MSB only */ struct GPatch * gusload(char *); @@ -128,12 +128,9 @@ struct SynthObject int curPoint; }; -struct SynthObject voices[MAX_VOICES] IDATA_ATTR; - - +struct SynthObject voices[MAX_VOICES] IBSS_ATTR; void sendEvent(struct Event * ev); -int tick(struct MIDIfile * mf); inline void setPoint(struct SynthObject * so, int pt); struct Event * getEvent(struct Track * tr, int evNum); int readTwoBytes(int file); @@ -196,8 +193,11 @@ void *alloc(int size) offset += size + 4; totalSize -= size + 4; return ret; -}*/ -void * allocate(int size) +} +*/ + +#define malloc(n) my_malloc(n) +void * my_malloc(int size) { return alloc(size); } @@ -211,7 +211,7 @@ unsigned char readChar(int file) unsigned char * readData(int file, int len) { - unsigned char * dat = allocate(len); + unsigned char * dat = malloc(len); rb->read(file, dat, len); return dat; } @@ -226,7 +226,29 @@ int eof(int fd) return size+1 == rb->lseek(fd, 0, SEEK_CUR); } -void printf(char *fmt, ...) {fmt=fmt; } +// Here is a hacked up printf command to get the output from the game. +int printf(const char *fmt, ...) +{ + static int p_xtpt; + char p_buf[50]; + bool ok; + va_list ap; + + va_start(ap, fmt); + ok = rb->vsnprintf(p_buf,sizeof(p_buf), fmt, ap); + va_end(ap); + + rb->lcd_putsxy(1,p_xtpt, (unsigned char *)p_buf); + rb->lcd_update(); + + p_xtpt+=8; + if(p_xtpt>LCD_HEIGHT-8) + { + p_xtpt=0; + rb->lcd_clear_display(); + } + return 1; +} void exit(int code) { diff --git a/apps/plugins/midi/sequencer.c b/apps/plugins/midi/sequencer.c index 4ae5a9f5fe..3c026276c2 100644 --- a/apps/plugins/midi/sequencer.c +++ b/apps/plugins/midi/sequencer.c @@ -22,22 +22,22 @@ extern struct plugin_api * rb; long tempo=375000; -void setVol(int ch, int vol) +inline void setVol(int ch, int vol) { - printf("\nvolume[%d] %d ==> %d", ch, chVol[ch], vol); +// printf("\nvolume[%d] %d ==> %d", ch, chVol[ch], vol); chVol[ch]=vol; } -void setPan(int ch, int pan) +inline void setPan(int ch, int pan) { - printf("\npanning[%d] %d ==> %d", ch, chPanRight[ch], pan); +// printf("\npanning[%d] %d ==> %d", ch, chPanRight[ch], pan); chPanLeft[ch]=128-pan; chPanRight[ch]=pan; } -void setPatch(int ch, int pat) +inline void setPatch(int ch, int pat) { chPat[ch]=pat; } @@ -52,18 +52,64 @@ void setPatch(int ch, int pat) /* long pitchTbl[]= { - 58386,58491,58597,58703,58809,58915,59022,59128,59235,59342,59449,59557,59664,59772,59880,59988,60097,60205, - 60314,60423,60532,60642,60751,60861,60971,61081,61191,61302,61413,61524,61635,61746,61858,61970,62081,62194, - 62306,62419,62531,62644,62757,62871,62984,63098,63212,63326,63441,63555,63670,63785,63901,64016,64132,64248, - 64364,64480,64596,64713,64830,64947,65065,65182,65300,65418,65536,65654,65773,65892,66011,66130,66250,66369, - 66489,66609,66730,66850,66971,67092,67213,67335,67456,67578,67700,67823,67945,68068,68191,68314,68438,68561, - 68685,68809,68933,69058,69183,69308,69433,69558,69684,69810,69936,70062,70189,70316,70443,70570,70698,70825, - 70953,71082,71210,71339,71468,71597,71726,71856,71985,72115,72246,72376,72507,72638,72769,72901,73032,73164, - 73297,73429 + 58386,58491,58597,58703,58809,58915,59022,59128,59235,59342,59449,59557, + 59664,59772,59880,59988,60097,60205,60314,60423,60532,60642,60751,60861, + 60971,61081,61191,61302,61413,61524,61635,61746,61858,61970,62081,62194, + 62306,62419,62531,62644,62757,62871,62984,63098,63212,63326,63441,63555, + 63670,63785,63901,64016,64132,64248,64364,64480,64596,64713,64830,64947, + 65065,65182,65300,65418,65536,65654,65773,65892,66011,66130,66250,66369, + 66489,66609,66730,66850,66971,67092,67213,67335,67456,67578,67700,67823, + 67945,68068,68191,68314,68438,68561,68685,68809,68933,69058,69183,69308, + 69433,69558,69684,69810,69936,70062,70189,70316,70443,70570,70698,70825, + 70953,71082,71210,71339,71468,71597,71726,71856,71985,72115,72246,72376, + 72507,72638,72769,72901,73032,73164,73297,73429 }; */ -long pitchTbl[]={ -58386,58412,58439,58465,58491,58518,58544,58571,58597,58624,58650,58676,58703,58729,58756,58782,58809,58836,58862,58889,58915,58942,58968,58995,59022,59048,59075,59102,59128,59155,59182,59208,59235,59262,59289,59315,59342,59369,59396,59423,59449,59476,59503,59530,59557,59584,59611,59638,59664,59691,59718,59745,59772,59799,59826,59853,59880,59907,59934,59961,59988,60015,60043,60070,60097,60124,60151,60178,60205,60233,60260,60287,60314,60341,60369,60396,60423,60450,60478,60505,60532,60560,60587,60614,60642,60669,60696,60724,60751,60779,60806,60833,60861,60888,60916,60943,60971,60998,61026,61054,61081,61109,61136,61164,61191,61219,61247,61274,61302,61330,61357,61385,61413,61440,61468,61496,61524,61551,61579,61607,61635,61663,61690,61718,61746,61774,61802,61830,61858,61886,61914,61942,61970,61997,62025,62053,62081,62109,62138,62166,62194,62222,62250,62278,62306,62334,62362,62390,62419,62447,62475,62503,62531,62560,62588,62616,62644,62673,62701,62729,62757,62786,62814,62843,62871,62899,62928,62956,62984,63013,63041,63070,63098,63127,63155,63184,63212,63241,63269,63298,63326,63355,63384,63412,63441,63470,63498,63527,63555,63584,63613,63642,63670,63699,63728,63757,63785,63814,63843,63872,63901,63929,63958,63987,64016,64045,64074,64103,64132,64161,64190,64219,64248,64277,64306,64335,64364,64393,64422,64451,64480,64509,64538,64567,64596,64626,64655,64684,64713,64742,64772,64801,64830,64859,64889,64918,64947,64976,65006,65035,65065,65094,65123,65153,65182,65211,65241,65270,65300,65329,65359,65388,65418,65447,65477,65506,65536,65566,65595,65625,65654,65684,65714,65743,65773,65803,65832,65862,65892,65922,65951,65981,66011,66041,66071,66100,66130,66160,66190,66220,66250,66280,66309,66339,66369,66399,66429,66459,66489,66519,66549,66579,66609,66639,66670,66700,66730,66760,66790,66820,66850,66880,66911,66941,66971,67001,67032,67062,67092,67122,67153,67183,67213,67244,67274,67304,67335,67365,67395,67426,67456,67487,67517,67548,67578,67609,67639,67670,67700,67731,67761,67792,67823,67853,67884,67915,67945,67976,68007,68037,68068,68099,68129,68160,68191,68222,68252,68283,68314,68345,68376,68407,68438,68468,68499,68530,68561,68592,68623,68654,68685,68716,68747,68778,68809,68840,68871,68902,68933,68965,68996,69027,69058,69089,69120,69152,69183,69214,69245,69276,69308,69339,69370,69402,69433,69464,69496,69527,69558,69590,69621,69653,69684,69716,69747,69778,69810,69841,69873,69905,69936,69968,69999,70031,70062,70094,70126,70157,70189,70221,70252,70284,70316,70348,70379,70411,70443,70475,70507,70538,70570,70602,70634,70666,70698,70730,70762,70793,70825,70857,70889,70921,70953,70985,71017,71049,71082,71114,71146,71178,71210,71242,71274,71306,71339,71371,71403,71435,71468,71500,71532,71564,71597,71629,71661,71694,71726,71758,71791,71823,71856,71888,71920,71953,71985,72018,72050,72083,72115,72148,72181,72213,72246,72278,72311,72344,72376,72409,72442,72474,72507,72540,72573,72605,72638,72671,72704,72736,72769,72802,72835,72868,72901,72934,72967,72999,73032,73065,73098,73131,73164,73197,73230,73264,73297,73330,73363,73396,73429,73462,73495,73528 + +long pitchTbl[] ICONST_ATTR={ + 58386,58412,58439,58465,58491,58518,58544,58571,58597,58624,58650,58676, + 58703,58729,58756,58782,58809,58836,58862,58889,58915,58942,58968,58995, + 59022,59048,59075,59102,59128,59155,59182,59208,59235,59262,59289,59315, + 59342,59369,59396,59423,59449,59476,59503,59530,59557,59584,59611,59638, + 59664,59691,59718,59745,59772,59799,59826,59853,59880,59907,59934,59961, + 59988,60015,60043,60070,60097,60124,60151,60178,60205,60233,60260,60287, + 60314,60341,60369,60396,60423,60450,60478,60505,60532,60560,60587,60614, + 60642,60669,60696,60724,60751,60779,60806,60833,60861,60888,60916,60943, + 60971,60998,61026,61054,61081,61109,61136,61164,61191,61219,61247,61274, + 61302,61330,61357,61385,61413,61440,61468,61496,61524,61551,61579,61607, + 61635,61663,61690,61718,61746,61774,61802,61830,61858,61886,61914,61942, + 61970,61997,62025,62053,62081,62109,62138,62166,62194,62222,62250,62278, + 62306,62334,62362,62390,62419,62447,62475,62503,62531,62560,62588,62616, + 62644,62673,62701,62729,62757,62786,62814,62843,62871,62899,62928,62956, + 62984,63013,63041,63070,63098,63127,63155,63184,63212,63241,63269,63298, + 63326,63355,63384,63412,63441,63470,63498,63527,63555,63584,63613,63642, + 63670,63699,63728,63757,63785,63814,63843,63872,63901,63929,63958,63987, + 64016,64045,64074,64103,64132,64161,64190,64219,64248,64277,64306,64335, + 64364,64393,64422,64451,64480,64509,64538,64567,64596,64626,64655,64684, + 64713,64742,64772,64801,64830,64859,64889,64918,64947,64976,65006,65035, + 65065,65094,65123,65153,65182,65211,65241,65270,65300,65329,65359,65388, + 65418,65447,65477,65506,65536,65566,65595,65625,65654,65684,65714,65743, + 65773,65803,65832,65862,65892,65922,65951,65981,66011,66041,66071,66100, + 66130,66160,66190,66220,66250,66280,66309,66339,66369,66399,66429,66459, + 66489,66519,66549,66579,66609,66639,66670,66700,66730,66760,66790,66820, + 66850,66880,66911,66941,66971,67001,67032,67062,67092,67122,67153,67183, + 67213,67244,67274,67304,67335,67365,67395,67426,67456,67487,67517,67548, + 67578,67609,67639,67670,67700,67731,67761,67792,67823,67853,67884,67915, + 67945,67976,68007,68037,68068,68099,68129,68160,68191,68222,68252,68283, + 68314,68345,68376,68407,68438,68468,68499,68530,68561,68592,68623,68654, + 68685,68716,68747,68778,68809,68840,68871,68902,68933,68965,68996,69027, + 69058,69089,69120,69152,69183,69214,69245,69276,69308,69339,69370,69402, + 69433,69464,69496,69527,69558,69590,69621,69653,69684,69716,69747,69778, + 69810,69841,69873,69905,69936,69968,69999,70031,70062,70094,70126,70157, + 70189,70221,70252,70284,70316,70348,70379,70411,70443,70475,70507,70538, + 70570,70602,70634,70666,70698,70730,70762,70793,70825,70857,70889,70921, + 70953,70985,71017,71049,71082,71114,71146,71178,71210,71242,71274,71306, + 71339,71371,71403,71435,71468,71500,71532,71564,71597,71629,71661,71694, + 71726,71758,71791,71823,71856,71888,71920,71953,71985,72018,72050,72083, + 72115,72148,72181,72213,72246,72278,72311,72344,72376,72409,72442,72474, + 72507,72540,72573,72605,72638,72671,72704,72736,72769,72802,72835,72868, + 72901,72934,72967,72999,73032,73065,73098,73131,73164,73197,73230,73264, + 73297,73330,73363,73396,73429,73462,73495,73528 }; void findDelta(struct SynthObject * so, int ch, int note) @@ -75,9 +121,9 @@ void findDelta(struct SynthObject * so, int ch, int note) so->delta = (so->delta * pitchTbl[chPW[ch]])>> 16; } -void setPW(int ch, int msb, int lsb) +inline void setPW(int ch, int msb, int lsb) { - printf("\npitchw[%d] %d ==> %d", ch, chPW[ch], msb); +// printf("\npitchw[%d] %d ==> %d", ch, chPW[ch], msb); chPW[ch] = msb<<2|lsb>>5; int a=0; @@ -92,7 +138,7 @@ void setPW(int ch, int msb, int lsb) void pressNote(int ch, int note, int vol) { - + static int lastKill = 0; //Silences all channels but one, for easy debugging, for me. /* if(ch == 0) return; @@ -123,11 +169,16 @@ void pressNote(int ch, int note, int vol) } if(a==MAX_VOICES-1) { - printf("\nOVERFLOW: Too many voices playing at once. No more left"); - printf("\nVOICE DUMP: "); - for(a=0; a<48; a++) - printf("\n#%d Ch=%d Note=%d curRate=%d curOffset=%d curPoint=%d targetOffset=%d", a, voices[a].ch, voices[a].note, voices[a].curRate, voices[a].curOffset, voices[a].curPoint, voices[a].targetOffset); - return; /* None available */ +// printf("\nVoice kill"); +// printf("\nToo many voices playing at once. No more left"); +// printf("\nVOICE DUMP: "); +// for(a=0; a<48; a++) +// printf("\n#%d Ch=%d Note=%d curRate=%d curOffset=%d curPoint=%d targetOffset=%d", a, voices[a].ch, voices[a].note, voices[a].curRate, voices[a].curOffset, voices[a].curPoint, voices[a].targetOffset); + lastKill++; + if(lastKill == MAX_VOICES) + lastKill = 0; + a = lastKill; +// return; /* None available */ } voices[a].ch=ch; voices[a].note=note; @@ -163,7 +214,7 @@ void pressNote(int ch, int note, int vol) voices[a].wf=wf; voices[a].delta = (((gustable[note]<<10) / wf->rootFreq) * wf->sampRate / SAMPLE_RATE); if(wf->mode & 28) - printf("\nWoah, a drum patch has a loop. Stripping the loop..."); +// printf("\nWoah, a drum patch has a loop. Stripping the loop..."); wf->mode = wf->mode & (255-28); /* Turn it on */ @@ -172,7 +223,7 @@ void pressNote(int ch, int note, int vol) } else { - printf("\nWarning: drum %d does not have a patch defined... Ignoring it", note); +/* printf("\nWarning: drum %d does not have a patch defined... Ignoring it", note); */ } } } @@ -244,11 +295,7 @@ void sendEvent(struct Event * ev) } } - - - - -int tick(struct MIDIfile * mf) +int tick(void) { if(mf==NULL) return 0; @@ -280,7 +327,7 @@ int tick(struct MIDIfile * mf) sendEvent(e); if(((e->status&0xF0) == MIDI_PRGM)) { - printf("\nPatch Event, patch[%d] ==> %d", e->status&0xF, e->d1); +/* printf("\nPatch Event, patch[%d] ==> %d", e->status&0xF, e->d1); */ } } else diff --git a/apps/plugins/midi/synth.c b/apps/plugins/midi/synth.c index 42ca9ddaf6..44417b2583 100644 --- a/apps/plugins/midi/synth.c +++ b/apps/plugins/midi/synth.c @@ -104,8 +104,9 @@ int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig) if( (getEvent(mf->tracks[a], ts)->status & 0xF0) == MIDI_PRGM) { - if(patchUsed[getEvent(mf->tracks[a], ts)->d1]==0) +/* if(patchUsed[getEvent(mf->tracks[a], ts)->d1]==0) printf("\nI need to load patch %d.", getEvent(mf->tracks[a], ts)->d1); +*/ patchUsed[getEvent(mf->tracks[a], ts)->d1]=1; } } @@ -124,13 +125,14 @@ int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig) /* Scan our config file and load the right patches as needed */ int c = 0; rb->snprintf(name, 40, ""); + printf("\nLoading instruments"); for(a=0; a<128; a++) { while(readChar(file)!=' ' && !eof(file)); readTextBlock(file, name); rb->snprintf(fn, 40, "/.rockbox/patchset/%s.pat", name); - printf("\nLOADING: <%s> ", fn); +/* printf("\nLOADING: <%s> ", fn); */ if(patchUsed[a]==1) { @@ -155,6 +157,7 @@ int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig) /* Scan our config file and load the drum data */ int idx=0; char number[30]; + printf("\nLoading drums"); while(!eof(file)) { readTextBlock(file, number); @@ -168,7 +171,6 @@ int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig) if(drumUsed[idx]==1) { drumSet[idx]=gusload(fn); - if(drumSet[idx] == NULL) /* Error loading patch */ return -1; } @@ -180,32 +182,14 @@ int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig) return 0; } - - -int currentVoice IDATA_ATTR; -struct SynthObject * so IDATA_ATTR; -struct GWaveform * wf IDATA_ATTR; -int s IDATA_ATTR; -short s1 IDATA_ATTR; -short s2 IDATA_ATTR; -short sample IDATA_ATTR; /* For synthSample */ -unsigned int cpShifted IDATA_ATTR; - -unsigned char b1 IDATA_ATTR; -unsigned char b2 IDATA_ATTR; - - -inline int getSample(int s) +inline short getSample(int s,struct GWaveform * wf ) { /* Sign conversion moved to guspat.c */ /* 8bit conversion NOT YET IMPLEMENTED in guspat.c */ return ((short *) wf->data)[s]; } - - - -inline void setPoint(struct SynthObject * so, int pt) +void setPoint(struct SynthObject * so, int pt) { if(so->ch==9) /* Drums, no ADSR */ { @@ -227,7 +211,7 @@ inline void setPoint(struct SynthObject * so, int pt) so->curPoint = pt; - int r=0; + int r; int rate = so->wf->envRate[pt]; r=3-((rate>>6) & 0x3); /* Some blatant Timidity code for rate conversion... */ @@ -243,15 +227,17 @@ inline void setPoint(struct SynthObject * so, int pt) * default this to 10, and maybe later have an option to set it to 9 * for longer decays. */ - so->curRate = r<<10; + so->curRate = r<<11; /* * Do this here because the patches assume a 44100 sampling rate * We've halved our sampling rate, ergo the ADSR code will be * called half the time. Ergo, double the rate to keep stuff * sounding right. + * + * Or just move the 1 up one line to optimize a tiny bit. */ - so->curRate = so->curRate << 1; +/* so->curRate = so->curRate << 1;*/ so->targetOffset = so->wf->envOffset[pt]<<(20); @@ -270,9 +256,14 @@ inline void stopVoice(struct SynthObject * so) } -inline signed short int synthVoice(void) +signed short int synthVoice(struct SynthObject * so) { - so = &voices[currentVoice]; + struct GWaveform * wf; + register int s; + register unsigned int cpShifted; + register short s1; + register short s2; + wf = so->wf; @@ -288,7 +279,7 @@ inline signed short int synthVoice(void) stopVoice(so); } - s2 = getSample((cpShifted)+1); + s2 = getSample((cpShifted)+1, wf); /* LOOP_REVERSE|LOOP_PINGPONG = 24 */ if((wf->mode & (24)) && so->loopState == STATE_LOOPING && (cpShifted <= (wf->startLoop))) @@ -297,8 +288,9 @@ inline signed short int synthVoice(void) { so->cp = (wf->endLoop)<<10; //Was 10 cpShifted = wf->endLoop; - s2=getSample((cpShifted)); - } else + s2=getSample((cpShifted), wf); + } + else { so->delta = -so->delta; so->loopDir = LOOPDIR_FORWARD; @@ -312,8 +304,9 @@ inline signed short int synthVoice(void) { so->cp = (wf->startLoop)<<10; //Was 10 cpShifted = wf->startLoop; - s2=getSample((cpShifted)); - } else + s2=getSample((cpShifted), wf); + } + else { so->delta = -so->delta; so->loopDir = LOOPDIR_REVERSE; @@ -321,7 +314,7 @@ inline signed short int synthVoice(void) } /* Better, working, linear interpolation */ - s1=getSample((cpShifted)); //\|/ Was 1023)) >> 10 + s1=getSample((cpShifted), wf); //\|/ Was 1023)) >> 10 s = s1 + ((signed)((s2 - s1) * (so->cp & 1023))>>10); //Was 10 @@ -381,18 +374,26 @@ inline signed short int synthVoice(void) inline void synthSample(int * mixL, int * mixR) { - *mixL = 0; - *mixR = 0; - for(currentVoice=0; currentVoiceisUsed==1) { - sample = synthVoice(); - *mixL += (sample*chPanLeft[voices[currentVoice].ch])>>7; - *mixR += (sample*chPanRight[voices[currentVoice].ch])>>7; + sample = synthVoice(voicept); + dL += (sample*chPanLeft[voicept->ch])>>7; + dR += (sample*chPanRight[voicept->ch])>>7; } + voicept++; } + *mixL=dL; + *mixR=dR; + /* TODO: Automatic Gain Control, anyone? */ /* Or, should this be implemented on the DSP's output volume instead? */ diff --git a/apps/plugins/midiplay.c b/apps/plugins/midiplay.c new file mode 100644 index 0000000000..f279e72e4e --- /dev/null +++ b/apps/plugins/midiplay.c @@ -0,0 +1,217 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2005 Karl Kurbjun based on midi2wav by Stepan Moskovchenko + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "../../plugin.h" + +PLUGIN_HEADER + +#define SAMPLE_RATE 22050 // 44100 22050 11025 +#define MAX_VOICES 12 // Note: 24 midi channels is the minimum general midi + // spec implementation +#define BUF_SIZE 512 +#define NBUF 2 + +#undef SYNC +struct MIDIfile * mf IBSS_ATTR; + +int numberOfSamples IBSS_ATTR; +long bpm IBSS_ATTR; + +#include "midi/midiutil.c" +#include "midi/guspat.h" +#include "midi/guspat.c" +#include "midi/sequencer.c" +#include "midi/midifile.c" +#include "midi/synth.c" + +short gmbuf[BUF_SIZE*NBUF] IBSS_ATTR; + +int quit=0; +struct plugin_api * rb; + +#ifdef USE_IRAM +extern char iramcopy[]; +extern char iramstart[]; +extern char iramend[]; +extern char iedata[]; +extern char iend[]; +#endif + +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) +{ + rb = api; + + if(parameter == NULL) + { + rb->splash(HZ*2, true, " Play .MID file "); + return PLUGIN_OK; + } + rb->lcd_setfont(0); + +#ifdef USE_IRAM + rb->memcpy(iramstart, iramcopy, iramend-iramstart); + rb->memset(iedata, 0, iend - iedata); +#endif + +#if !defined(SIMULATOR) && defined(HAVE_ADJUSTABLE_CPU_FREQ) + rb->cpu_boost(true); +#endif + + printf("\n%s", parameter); +/* rb->splash(HZ, true, parameter); */ + +#ifdef RB_PROFILE + rb->profile_thread(); +#endif + + if(midimain(parameter) == -1) + return PLUGIN_ERROR; + +#ifdef RB_PROFILE + rb->profstop(); +#endif + +#ifndef SIMULATOR + rb->pcm_play_stop(); + rb->pcm_set_frequency(44100); // 44100 +#endif + +#if !defined(SIMULATOR) && defined(HAVE_ADJUSTABLE_CPU_FREQ) + rb->cpu_boost(false); +#endif + + rb->splash(HZ, true, "FINISHED PLAYING"); + + return PLUGIN_OK; +} + +bool swap=0; +bool lastswap=1; + +inline void synthbuf(void) +{ + short *outptr; + register int i; + static int currentSample=0; + int synthtemp[2]; + +#ifndef SYNC + if(lastswap==swap) return; + lastswap=swap; + + outptr=(swap ? gmbuf : gmbuf+BUF_SIZE); +#else + outptr=gmbuf; +#endif + + for(i=0; isplash(HZ/5, true, "LOADING MIDI"); */ + printf("\nLoading file"); + mf= loadFile(filename); + +/* rb->splash(HZ/5, true, "LOADING PATCHES"); */ + if (initSynth(mf, "/.rockbox/patchset/patchset.cfg", "/.rockbox/patchset/drums.cfg") == -1) + return -1; + +#ifndef SIMULATOR + rb->pcm_play_stop(); + rb->pcm_set_frequency(SAMPLE_RATE); // 44100 22050 11025 +#endif + + /* + * 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. + */ + + printf("\nOkay, starting sequencing"); + + bpm=mf->div*1000000/tempo; + numberOfSamples=SAMPLE_RATE/bpm; + + tick(); + + synthbuf(); +#ifndef SIMULATOR + rb->pcm_play_data(&get_more, NULL, 0); +#endif + + button=rb->button_status(); + + while(!quit) + { +#ifndef SYNC + synthbuf(); +#endif + rb->yield(); + if(rb->button_status()!=button) quit=1; + } + + return 0; +} diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config index 6de2bd883a..afab02278b 100644 --- a/apps/plugins/viewers.config +++ b/apps/plugins/viewers.config @@ -11,7 +11,7 @@ txt,viewers/sort, 00 00 00 00 00 00 gb,viewers/rockboy, 0C 2A 59 7A 2E 0C gbc,viewers/rockboy, 0C 2A 59 7A 2E 0C m3u,viewers/iriverify,00 00 00 00 00 00 -mid,viewers/midi2wav, 20 70 70 3F 00 00 +mid,viewers/midiplay, 20 70 70 3F 00 00 rsp,viewers/searchengine, 0e 11 11 31 7e 60 ss,rocks/sudoku, 55 55 55 55 55 55 wav,viewers/wav2wv, 00 00 00 00 00 00 -- cgit v1.2.3