summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
authorStepan Moskovchenko <stevenm@rockbox.org>2006-05-01 23:22:59 +0000
committerStepan Moskovchenko <stevenm@rockbox.org>2006-05-01 23:22:59 +0000
commitb2f1b5dd183b1171c81796946c868f2df8df9647 (patch)
tree3f2fcd3bdf2e2f9e00ad253d671b5c27a52280ad /apps/plugins
parent9e3da0d6d5bc9d02b939dedd62e05f8893940c1a (diff)
downloadrockbox-b2f1b5dd183b1171c81796946c868f2df8df9647.tar.gz
rockbox-b2f1b5dd183b1171c81796946c868f2df8df9647.zip
----------------------------------------------------------------------
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
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/SOURCES2
-rw-r--r--apps/plugins/midi/guspat.c14
-rw-r--r--apps/plugins/midi/midifile.c40
-rw-r--r--apps/plugins/midi/midiutil.c48
-rw-r--r--apps/plugins/midi/sequencer.c109
-rw-r--r--apps/plugins/midi/synth.c83
-rw-r--r--apps/plugins/midiplay.c217
-rw-r--r--apps/plugins/viewers.config2
8 files changed, 400 insertions, 115 deletions
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
99 99
100#if CONFIG_CODEC == SWCODEC /* software codec platforms */ 100#if CONFIG_CODEC == SWCODEC /* software codec platforms */
101mp3_encoder.c 101mp3_encoder.c
102midi2wav.c 102midiplay.c
103wav2wv.c 103wav2wv.c
104#else /* hardware codec platforms */ 104#else /* hardware codec platforms */
105#ifndef HAVE_MMC /* not for Ondio, has no remote control pin */ 105#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)
31 31
32struct GWaveform * loadWaveform(int file) 32struct GWaveform * loadWaveform(int file)
33{ 33{
34 struct GWaveform * wav = (struct GWaveform *)allocate(sizeof(struct GWaveform)); 34 struct GWaveform * wav = (struct GWaveform *)malloc(sizeof(struct GWaveform));
35 rb->memset(wav, 0, sizeof(struct GWaveform)); 35 rb->memset(wav, 0, sizeof(struct GWaveform));
36 36
37 wav->name=readData(file, 7); 37 wav->name=readData(file, 7);
38 printf("\nWAVE NAME = [%s]", wav->name); 38/* printf("\nWAVE NAME = [%s]", wav->name); */
39 wav->fractions=readChar(file); 39 wav->fractions=readChar(file);
40 wav->wavSize=readDWord(file); 40 wav->wavSize=readDWord(file);
41 wav->startLoop=readDWord(file); 41 wav->startLoop=readDWord(file);
@@ -62,7 +62,7 @@ struct GWaveform * loadWaveform(int file)
62 62
63 wav->scaleFreq=readWord(file); 63 wav->scaleFreq=readWord(file);
64 wav->scaleFactor=readWord(file); 64 wav->scaleFactor=readWord(file);
65 printf("\nScaleFreq = %d ScaleFactor = %d RootFreq = %d", wav->scaleFreq, wav->scaleFactor, wav->rootFreq); 65/* printf("\nScaleFreq = %d ScaleFactor = %d RootFreq = %d", wav->scaleFreq, wav->scaleFactor, wav->rootFreq); */
66 wav->res=readData(file, 36); 66 wav->res=readData(file, 36);
67 wav->data=readData(file, wav->wavSize); 67 wav->data=readData(file, wav->wavSize);
68 68
@@ -137,7 +137,7 @@ int selectWaveform(struct GPatch * pat, int midiNote)
137 137
138struct GPatch * gusload(char * filename) 138struct GPatch * gusload(char * filename)
139{ 139{
140 struct GPatch * gp = (struct GPatch *)allocate(sizeof(struct GPatch)); 140 struct GPatch * gp = (struct GPatch *)malloc(sizeof(struct GPatch));
141 rb->memset(gp, 0, sizeof(struct GPatch)); 141 rb->memset(gp, 0, sizeof(struct GPatch));
142 142
143 int file = rb->open(filename, O_RDONLY); 143 int file = rb->open(filename, O_RDONLY);
@@ -175,15 +175,15 @@ struct GPatch * gusload(char * filename)
175 gp->layerRes=readData(file,40); 175 gp->layerRes=readData(file,40);
176 176
177 177
178 printf("\nFILE: %s", filename); 178/* printf("\nFILE: %s", filename); */
179 printf("\nlayerSamples=%d", gp->numWaves); 179/* printf("\nlayerSamples=%d", gp->numWaves); */
180 180
181 int a=0; 181 int a=0;
182 for(a=0; a<gp->numWaves; a++) 182 for(a=0; a<gp->numWaves; a++)
183 gp->waveforms[a] = loadWaveform(file); 183 gp->waveforms[a] = loadWaveform(file);
184 184
185 185
186 printf("\nPrecomputing note table"); 186/* printf("\nPrecomputing note table"); */
187 187
188 for(a=0; a<128; a++) 188 for(a=0; a<128; a++)
189 { 189 {
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 *);
26 26
27struct MIDIfile * loadFile(char * filename) 27struct MIDIfile * loadFile(char * filename)
28{ 28{
29 struct MIDIfile * mf; 29 struct MIDIfile * mfload;
30 int file = rb->open (filename, O_RDONLY); 30 int file = rb->open (filename, O_RDONLY);
31 31
32 if(file==-1) 32 if(file==-1)
@@ -34,15 +34,15 @@ struct MIDIfile * loadFile(char * filename)
34 bail("Could not open file\n"); 34 bail("Could not open file\n");
35 } 35 }
36 36
37 mf = (struct MIDIfile*)allocate(sizeof(struct MIDIfile)); 37 mfload = (struct MIDIfile*)malloc(sizeof(struct MIDIfile));
38 38
39 if(mf==NULL) 39 if(mfload==NULL)
40 { 40 {
41 rb->close(file); 41 rb->close(file);
42 bail("Could not allocate memory for MIDIfile struct\n"); 42 bail("Could not allocate memory for MIDIfile struct\n");
43 } 43 }
44 44
45 rb->memset(mf, 0, sizeof(struct MIDIfile)); 45 rb->memset(mfload, 0, sizeof(struct MIDIfile));
46 46
47 if(readID(file) != ID_MTHD) 47 if(readID(file) != ID_MTHD)
48 { 48 {
@@ -62,32 +62,32 @@ struct MIDIfile * loadFile(char * filename)
62 bail("MIDI file type not supported"); 62 bail("MIDI file type not supported");
63 } 63 }
64 64
65 mf->numTracks = readTwoBytes(file); 65 mfload->numTracks = readTwoBytes(file);
66 mf->div = readTwoBytes(file); 66 mfload->div = readTwoBytes(file);
67 67
68 int track=0; 68 int track=0;
69 69
70 printf("\nnumTracks=%d div=%d\nBegin reading track data\n", mf->numTracks, mf->div); 70 printf("\nnumTracks=%d div=%d\nBegin reading track data\n", mfload->numTracks, mfload->div);
71 71
72 72
73 while(! eof(file) && track < mf->numTracks) 73 while(! eof(file) && track < mfload->numTracks)
74 { 74 {
75 unsigned char id = readID(file); 75 unsigned char id = readID(file);
76 76
77 77
78 if(id == ID_EOF) 78 if(id == ID_EOF)
79 { 79 {
80 if(mf->numTracks != track) 80 if(mfload->numTracks != track)
81 { 81 {
82 printf("\nError: file claims to have %d tracks.\n I only see %d here.\n", mf->numTracks, track); 82 printf("\nError: file claims to have %d tracks.\n I only see %d here.\n", mfload->numTracks, track);
83 mf->numTracks = track; 83 mfload->numTracks = track;
84 } 84 }
85 return mf; 85 return mfload;
86 } 86 }
87 87
88 if(id == ID_MTRK) 88 if(id == ID_MTRK)
89 { 89 {
90 mf->tracks[track] = readTrack(file); 90 mfload->tracks[track] = readTrack(file);
91 //exit(0); 91 //exit(0);
92 track++; 92 track++;
93 } else 93 } else
@@ -98,16 +98,16 @@ struct MIDIfile * loadFile(char * filename)
98 readChar(file); 98 readChar(file);
99 } 99 }
100 } 100 }
101 return mf; 101 return mfload;
102 102
103} 103}
104 104
105 105
106int rStatus = 0;
107
108/* Returns 0 if done, 1 if keep going */ 106/* Returns 0 if done, 1 if keep going */
109int readEvent(int file, void * dest) 107int readEvent(int file, void * dest)
110{ 108{
109
110 static int rStatus = 0;
111 struct Event dummy; 111 struct Event dummy;
112 struct Event * ev = (struct Event *) dest; 112 struct Event * ev = (struct Event *) dest;
113 113
@@ -131,7 +131,7 @@ int readEvent(int file, void * dest)
131 if(dest != NULL) 131 if(dest != NULL)
132 { 132 {
133 ev->evData = readData(file, ev->len); 133 ev->evData = readData(file, ev->len);
134 printf("\nDATA: <%s>", ev->evData); 134/* printf("\nDATA: <%s>", ev->evData); */
135 } 135 }
136 else 136 else
137 { 137 {
@@ -173,11 +173,9 @@ int readEvent(int file, void * dest)
173 return 1; 173 return 1;
174} 174}
175 175
176
177
178struct Track * readTrack(int file) 176struct Track * readTrack(int file)
179{ 177{
180 struct Track * trk = (struct Track *)allocate(sizeof(struct Track)); 178 struct Track * trk = (struct Track *)malloc(sizeof(struct Track));
181 rb->memset(trk, 0, sizeof(struct Track)); 179 rb->memset(trk, 0, sizeof(struct Track));
182 180
183 trk->size = readFourBytes(file); 181 trk->size = readFourBytes(file);
@@ -194,7 +192,7 @@ struct Track * readTrack(int file)
194 rb->lseek(file, pos, SEEK_SET); 192 rb->lseek(file, pos, SEEK_SET);
195 193
196 int trackSize = (numEvents+1) * sizeof(struct Event); 194 int trackSize = (numEvents+1) * sizeof(struct Event);
197 void * dataPtr = allocate(trackSize); 195 void * dataPtr = malloc(trackSize);
198 trk->dataBlock = dataPtr; 196 trk->dataBlock = dataPtr;
199 197
200 numEvents=0; 198 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 @@
63extern struct plugin_api * rb; 63extern struct plugin_api * rb;
64 64
65 65
66int chVol[16] IDATA_ATTR; /* Channel volume */ 66int chVol[16] IBSS_ATTR; /* Channel volume */
67int chPanLeft[16] IDATA_ATTR; /* Channel panning */ 67int chPanLeft[16] IBSS_ATTR; /* Channel panning */
68int chPanRight[16] IDATA_ATTR; 68int chPanRight[16] IBSS_ATTR;
69int chPat[16]; /* Channel patch */ 69int chPat[16] IBSS_ATTR; /* Channel patch */
70int chPW[16]; /* Channel pitch wheel, MSB only */ 70int chPW[16] IBSS_ATTR; /* Channel pitch wheel, MSB only */
71 71
72 72
73struct GPatch * gusload(char *); 73struct GPatch * gusload(char *);
@@ -128,12 +128,9 @@ struct SynthObject
128 int curPoint; 128 int curPoint;
129}; 129};
130 130
131struct SynthObject voices[MAX_VOICES] IDATA_ATTR; 131struct SynthObject voices[MAX_VOICES] IBSS_ATTR;
132
133
134 132
135void sendEvent(struct Event * ev); 133void sendEvent(struct Event * ev);
136int tick(struct MIDIfile * mf);
137inline void setPoint(struct SynthObject * so, int pt); 134inline void setPoint(struct SynthObject * so, int pt);
138struct Event * getEvent(struct Track * tr, int evNum); 135struct Event * getEvent(struct Track * tr, int evNum);
139int readTwoBytes(int file); 136int readTwoBytes(int file);
@@ -196,8 +193,11 @@ void *alloc(int size)
196 offset += size + 4; 193 offset += size + 4;
197 totalSize -= size + 4; 194 totalSize -= size + 4;
198 return ret; 195 return ret;
199}*/ 196}
200void * allocate(int size) 197*/
198
199#define malloc(n) my_malloc(n)
200void * my_malloc(int size)
201{ 201{
202 return alloc(size); 202 return alloc(size);
203} 203}
@@ -211,7 +211,7 @@ unsigned char readChar(int file)
211 211
212unsigned char * readData(int file, int len) 212unsigned char * readData(int file, int len)
213{ 213{
214 unsigned char * dat = allocate(len); 214 unsigned char * dat = malloc(len);
215 rb->read(file, dat, len); 215 rb->read(file, dat, len);
216 return dat; 216 return dat;
217} 217}
@@ -226,7 +226,29 @@ int eof(int fd)
226 return size+1 == rb->lseek(fd, 0, SEEK_CUR); 226 return size+1 == rb->lseek(fd, 0, SEEK_CUR);
227} 227}
228 228
229void printf(char *fmt, ...) {fmt=fmt; } 229// Here is a hacked up printf command to get the output from the game.
230int printf(const char *fmt, ...)
231{
232 static int p_xtpt;
233 char p_buf[50];
234 bool ok;
235 va_list ap;
236
237 va_start(ap, fmt);
238 ok = rb->vsnprintf(p_buf,sizeof(p_buf), fmt, ap);
239 va_end(ap);
240
241 rb->lcd_putsxy(1,p_xtpt, (unsigned char *)p_buf);
242 rb->lcd_update();
243
244 p_xtpt+=8;
245 if(p_xtpt>LCD_HEIGHT-8)
246 {
247 p_xtpt=0;
248 rb->lcd_clear_display();
249 }
250 return 1;
251}
230 252
231void exit(int code) 253void exit(int code)
232{ 254{
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;
22long tempo=375000; 22long tempo=375000;
23 23
24 24
25void setVol(int ch, int vol) 25inline void setVol(int ch, int vol)
26{ 26{
27 printf("\nvolume[%d] %d ==> %d", ch, chVol[ch], vol); 27// printf("\nvolume[%d] %d ==> %d", ch, chVol[ch], vol);
28 chVol[ch]=vol; 28 chVol[ch]=vol;
29} 29}
30 30
31void setPan(int ch, int pan) 31inline void setPan(int ch, int pan)
32{ 32{
33 printf("\npanning[%d] %d ==> %d", ch, chPanRight[ch], pan); 33// printf("\npanning[%d] %d ==> %d", ch, chPanRight[ch], pan);
34 34
35 chPanLeft[ch]=128-pan; 35 chPanLeft[ch]=128-pan;
36 chPanRight[ch]=pan; 36 chPanRight[ch]=pan;
37} 37}
38 38
39 39
40void setPatch(int ch, int pat) 40inline void setPatch(int ch, int pat)
41{ 41{
42 chPat[ch]=pat; 42 chPat[ch]=pat;
43} 43}
@@ -52,18 +52,64 @@ void setPatch(int ch, int pat)
52/* 52/*
53long pitchTbl[]= 53long pitchTbl[]=
54{ 54{
55 58386,58491,58597,58703,58809,58915,59022,59128,59235,59342,59449,59557,59664,59772,59880,59988,60097,60205, 55 58386,58491,58597,58703,58809,58915,59022,59128,59235,59342,59449,59557,
56 60314,60423,60532,60642,60751,60861,60971,61081,61191,61302,61413,61524,61635,61746,61858,61970,62081,62194, 56 59664,59772,59880,59988,60097,60205,60314,60423,60532,60642,60751,60861,
57 62306,62419,62531,62644,62757,62871,62984,63098,63212,63326,63441,63555,63670,63785,63901,64016,64132,64248, 57 60971,61081,61191,61302,61413,61524,61635,61746,61858,61970,62081,62194,
58 64364,64480,64596,64713,64830,64947,65065,65182,65300,65418,65536,65654,65773,65892,66011,66130,66250,66369, 58 62306,62419,62531,62644,62757,62871,62984,63098,63212,63326,63441,63555,
59 66489,66609,66730,66850,66971,67092,67213,67335,67456,67578,67700,67823,67945,68068,68191,68314,68438,68561, 59 63670,63785,63901,64016,64132,64248,64364,64480,64596,64713,64830,64947,
60 68685,68809,68933,69058,69183,69308,69433,69558,69684,69810,69936,70062,70189,70316,70443,70570,70698,70825, 60 65065,65182,65300,65418,65536,65654,65773,65892,66011,66130,66250,66369,
61 70953,71082,71210,71339,71468,71597,71726,71856,71985,72115,72246,72376,72507,72638,72769,72901,73032,73164, 61 66489,66609,66730,66850,66971,67092,67213,67335,67456,67578,67700,67823,
62 73297,73429 62 67945,68068,68191,68314,68438,68561,68685,68809,68933,69058,69183,69308,
63 69433,69558,69684,69810,69936,70062,70189,70316,70443,70570,70698,70825,
64 70953,71082,71210,71339,71468,71597,71726,71856,71985,72115,72246,72376,
65 72507,72638,72769,72901,73032,73164,73297,73429
63}; 66};
64*/ 67*/
65long pitchTbl[]={ 68
6658386,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 69long pitchTbl[] ICONST_ATTR={
70 58386,58412,58439,58465,58491,58518,58544,58571,58597,58624,58650,58676,
71 58703,58729,58756,58782,58809,58836,58862,58889,58915,58942,58968,58995,
72 59022,59048,59075,59102,59128,59155,59182,59208,59235,59262,59289,59315,
73 59342,59369,59396,59423,59449,59476,59503,59530,59557,59584,59611,59638,
74 59664,59691,59718,59745,59772,59799,59826,59853,59880,59907,59934,59961,
75 59988,60015,60043,60070,60097,60124,60151,60178,60205,60233,60260,60287,
76 60314,60341,60369,60396,60423,60450,60478,60505,60532,60560,60587,60614,
77 60642,60669,60696,60724,60751,60779,60806,60833,60861,60888,60916,60943,
78 60971,60998,61026,61054,61081,61109,61136,61164,61191,61219,61247,61274,
79 61302,61330,61357,61385,61413,61440,61468,61496,61524,61551,61579,61607,
80 61635,61663,61690,61718,61746,61774,61802,61830,61858,61886,61914,61942,
81 61970,61997,62025,62053,62081,62109,62138,62166,62194,62222,62250,62278,
82 62306,62334,62362,62390,62419,62447,62475,62503,62531,62560,62588,62616,
83 62644,62673,62701,62729,62757,62786,62814,62843,62871,62899,62928,62956,
84 62984,63013,63041,63070,63098,63127,63155,63184,63212,63241,63269,63298,
85 63326,63355,63384,63412,63441,63470,63498,63527,63555,63584,63613,63642,
86 63670,63699,63728,63757,63785,63814,63843,63872,63901,63929,63958,63987,
87 64016,64045,64074,64103,64132,64161,64190,64219,64248,64277,64306,64335,
88 64364,64393,64422,64451,64480,64509,64538,64567,64596,64626,64655,64684,
89 64713,64742,64772,64801,64830,64859,64889,64918,64947,64976,65006,65035,
90 65065,65094,65123,65153,65182,65211,65241,65270,65300,65329,65359,65388,
91 65418,65447,65477,65506,65536,65566,65595,65625,65654,65684,65714,65743,
92 65773,65803,65832,65862,65892,65922,65951,65981,66011,66041,66071,66100,
93 66130,66160,66190,66220,66250,66280,66309,66339,66369,66399,66429,66459,
94 66489,66519,66549,66579,66609,66639,66670,66700,66730,66760,66790,66820,
95 66850,66880,66911,66941,66971,67001,67032,67062,67092,67122,67153,67183,
96 67213,67244,67274,67304,67335,67365,67395,67426,67456,67487,67517,67548,
97 67578,67609,67639,67670,67700,67731,67761,67792,67823,67853,67884,67915,
98 67945,67976,68007,68037,68068,68099,68129,68160,68191,68222,68252,68283,
99 68314,68345,68376,68407,68438,68468,68499,68530,68561,68592,68623,68654,
100 68685,68716,68747,68778,68809,68840,68871,68902,68933,68965,68996,69027,
101 69058,69089,69120,69152,69183,69214,69245,69276,69308,69339,69370,69402,
102 69433,69464,69496,69527,69558,69590,69621,69653,69684,69716,69747,69778,
103 69810,69841,69873,69905,69936,69968,69999,70031,70062,70094,70126,70157,
104 70189,70221,70252,70284,70316,70348,70379,70411,70443,70475,70507,70538,
105 70570,70602,70634,70666,70698,70730,70762,70793,70825,70857,70889,70921,
106 70953,70985,71017,71049,71082,71114,71146,71178,71210,71242,71274,71306,
107 71339,71371,71403,71435,71468,71500,71532,71564,71597,71629,71661,71694,
108 71726,71758,71791,71823,71856,71888,71920,71953,71985,72018,72050,72083,
109 72115,72148,72181,72213,72246,72278,72311,72344,72376,72409,72442,72474,
110 72507,72540,72573,72605,72638,72671,72704,72736,72769,72802,72835,72868,
111 72901,72934,72967,72999,73032,73065,73098,73131,73164,73197,73230,73264,
112 73297,73330,73363,73396,73429,73462,73495,73528
67}; 113};
68 114
69void findDelta(struct SynthObject * so, int ch, int note) 115void findDelta(struct SynthObject * so, int ch, int note)
@@ -75,9 +121,9 @@ void findDelta(struct SynthObject * so, int ch, int note)
75 so->delta = (so->delta * pitchTbl[chPW[ch]])>> 16; 121 so->delta = (so->delta * pitchTbl[chPW[ch]])>> 16;
76} 122}
77 123
78void setPW(int ch, int msb, int lsb) 124inline void setPW(int ch, int msb, int lsb)
79{ 125{
80 printf("\npitchw[%d] %d ==> %d", ch, chPW[ch], msb); 126// printf("\npitchw[%d] %d ==> %d", ch, chPW[ch], msb);
81 chPW[ch] = msb<<2|lsb>>5; 127 chPW[ch] = msb<<2|lsb>>5;
82 128
83 int a=0; 129 int a=0;
@@ -92,7 +138,7 @@ void setPW(int ch, int msb, int lsb)
92 138
93void pressNote(int ch, int note, int vol) 139void pressNote(int ch, int note, int vol)
94{ 140{
95 141 static int lastKill = 0;
96//Silences all channels but one, for easy debugging, for me. 142//Silences all channels but one, for easy debugging, for me.
97/* 143/*
98 if(ch == 0) return; 144 if(ch == 0) return;
@@ -123,11 +169,16 @@ void pressNote(int ch, int note, int vol)
123 } 169 }
124 if(a==MAX_VOICES-1) 170 if(a==MAX_VOICES-1)
125 { 171 {
126 printf("\nOVERFLOW: Too many voices playing at once. No more left"); 172// printf("\nVoice kill");
127 printf("\nVOICE DUMP: "); 173// printf("\nToo many voices playing at once. No more left");
128 for(a=0; a<48; a++) 174// printf("\nVOICE DUMP: ");
129 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); 175// for(a=0; a<48; a++)
130 return; /* None available */ 176// 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);
177 lastKill++;
178 if(lastKill == MAX_VOICES)
179 lastKill = 0;
180 a = lastKill;
181// return; /* None available */
131 } 182 }
132 voices[a].ch=ch; 183 voices[a].ch=ch;
133 voices[a].note=note; 184 voices[a].note=note;
@@ -163,7 +214,7 @@ void pressNote(int ch, int note, int vol)
163 voices[a].wf=wf; 214 voices[a].wf=wf;
164 voices[a].delta = (((gustable[note]<<10) / wf->rootFreq) * wf->sampRate / SAMPLE_RATE); 215 voices[a].delta = (((gustable[note]<<10) / wf->rootFreq) * wf->sampRate / SAMPLE_RATE);
165 if(wf->mode & 28) 216 if(wf->mode & 28)
166 printf("\nWoah, a drum patch has a loop. Stripping the loop..."); 217// printf("\nWoah, a drum patch has a loop. Stripping the loop...");
167 wf->mode = wf->mode & (255-28); 218 wf->mode = wf->mode & (255-28);
168 219
169 /* Turn it on */ 220 /* Turn it on */
@@ -172,7 +223,7 @@ void pressNote(int ch, int note, int vol)
172 223
173 } else 224 } else
174 { 225 {
175 printf("\nWarning: drum %d does not have a patch defined... Ignoring it", note); 226/* printf("\nWarning: drum %d does not have a patch defined... Ignoring it", note); */
176 } 227 }
177 } 228 }
178} 229}
@@ -244,11 +295,7 @@ void sendEvent(struct Event * ev)
244 } 295 }
245} 296}
246 297
247 298int tick(void)
248
249
250
251int tick(struct MIDIfile * mf)
252{ 299{
253 if(mf==NULL) 300 if(mf==NULL)
254 return 0; 301 return 0;
@@ -280,7 +327,7 @@ int tick(struct MIDIfile * mf)
280 sendEvent(e); 327 sendEvent(e);
281 if(((e->status&0xF0) == MIDI_PRGM)) 328 if(((e->status&0xF0) == MIDI_PRGM))
282 { 329 {
283 printf("\nPatch Event, patch[%d] ==> %d", e->status&0xF, e->d1); 330/* printf("\nPatch Event, patch[%d] ==> %d", e->status&0xF, e->d1); */
284 } 331 }
285 } 332 }
286 else 333 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)
104 104
105 if( (getEvent(mf->tracks[a], ts)->status & 0xF0) == MIDI_PRGM) 105 if( (getEvent(mf->tracks[a], ts)->status & 0xF0) == MIDI_PRGM)
106 { 106 {
107 if(patchUsed[getEvent(mf->tracks[a], ts)->d1]==0) 107/* if(patchUsed[getEvent(mf->tracks[a], ts)->d1]==0)
108 printf("\nI need to load patch %d.", getEvent(mf->tracks[a], ts)->d1); 108 printf("\nI need to load patch %d.", getEvent(mf->tracks[a], ts)->d1);
109*/
109 patchUsed[getEvent(mf->tracks[a], ts)->d1]=1; 110 patchUsed[getEvent(mf->tracks[a], ts)->d1]=1;
110 } 111 }
111 } 112 }
@@ -124,13 +125,14 @@ int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig)
124 /* Scan our config file and load the right patches as needed */ 125 /* Scan our config file and load the right patches as needed */
125 int c = 0; 126 int c = 0;
126 rb->snprintf(name, 40, ""); 127 rb->snprintf(name, 40, "");
128 printf("\nLoading instruments");
127 for(a=0; a<128; a++) 129 for(a=0; a<128; a++)
128 { 130 {
129 while(readChar(file)!=' ' && !eof(file)); 131 while(readChar(file)!=' ' && !eof(file));
130 readTextBlock(file, name); 132 readTextBlock(file, name);
131 133
132 rb->snprintf(fn, 40, "/.rockbox/patchset/%s.pat", name); 134 rb->snprintf(fn, 40, "/.rockbox/patchset/%s.pat", name);
133 printf("\nLOADING: <%s> ", fn); 135/* printf("\nLOADING: <%s> ", fn); */
134 136
135 if(patchUsed[a]==1) 137 if(patchUsed[a]==1)
136 { 138 {
@@ -155,6 +157,7 @@ int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig)
155 /* Scan our config file and load the drum data */ 157 /* Scan our config file and load the drum data */
156 int idx=0; 158 int idx=0;
157 char number[30]; 159 char number[30];
160 printf("\nLoading drums");
158 while(!eof(file)) 161 while(!eof(file))
159 { 162 {
160 readTextBlock(file, number); 163 readTextBlock(file, number);
@@ -168,7 +171,6 @@ int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig)
168 if(drumUsed[idx]==1) 171 if(drumUsed[idx]==1)
169 { 172 {
170 drumSet[idx]=gusload(fn); 173 drumSet[idx]=gusload(fn);
171
172 if(drumSet[idx] == NULL) /* Error loading patch */ 174 if(drumSet[idx] == NULL) /* Error loading patch */
173 return -1; 175 return -1;
174 } 176 }
@@ -180,32 +182,14 @@ int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig)
180 return 0; 182 return 0;
181} 183}
182 184
183 185inline short getSample(int s,struct GWaveform * wf )
184
185int currentVoice IDATA_ATTR;
186struct SynthObject * so IDATA_ATTR;
187struct GWaveform * wf IDATA_ATTR;
188int s IDATA_ATTR;
189short s1 IDATA_ATTR;
190short s2 IDATA_ATTR;
191short sample IDATA_ATTR; /* For synthSample */
192unsigned int cpShifted IDATA_ATTR;
193
194unsigned char b1 IDATA_ATTR;
195unsigned char b2 IDATA_ATTR;
196
197
198inline int getSample(int s)
199{ 186{
200 /* Sign conversion moved to guspat.c */ 187 /* Sign conversion moved to guspat.c */
201 /* 8bit conversion NOT YET IMPLEMENTED in guspat.c */ 188 /* 8bit conversion NOT YET IMPLEMENTED in guspat.c */
202 return ((short *) wf->data)[s]; 189 return ((short *) wf->data)[s];
203} 190}
204 191
205 192void setPoint(struct SynthObject * so, int pt)
206
207
208inline void setPoint(struct SynthObject * so, int pt)
209{ 193{
210 if(so->ch==9) /* Drums, no ADSR */ 194 if(so->ch==9) /* Drums, no ADSR */
211 { 195 {
@@ -227,7 +211,7 @@ inline void setPoint(struct SynthObject * so, int pt)
227 211
228 so->curPoint = pt; 212 so->curPoint = pt;
229 213
230 int r=0; 214 int r;
231 int rate = so->wf->envRate[pt]; 215 int rate = so->wf->envRate[pt];
232 216
233 r=3-((rate>>6) & 0x3); /* Some blatant Timidity code for rate conversion... */ 217 r=3-((rate>>6) & 0x3); /* Some blatant Timidity code for rate conversion... */
@@ -243,15 +227,17 @@ inline void setPoint(struct SynthObject * so, int pt)
243 * default this to 10, and maybe later have an option to set it to 9 227 * default this to 10, and maybe later have an option to set it to 9
244 * for longer decays. 228 * for longer decays.
245 */ 229 */
246 so->curRate = r<<10; 230 so->curRate = r<<11;
247 231
248 /* 232 /*
249 * Do this here because the patches assume a 44100 sampling rate 233 * Do this here because the patches assume a 44100 sampling rate
250 * We've halved our sampling rate, ergo the ADSR code will be 234 * We've halved our sampling rate, ergo the ADSR code will be
251 * called half the time. Ergo, double the rate to keep stuff 235 * called half the time. Ergo, double the rate to keep stuff
252 * sounding right. 236 * sounding right.
237 *
238 * Or just move the 1 up one line to optimize a tiny bit.
253 */ 239 */
254 so->curRate = so->curRate << 1; 240/* so->curRate = so->curRate << 1;*/
255 241
256 242
257 so->targetOffset = so->wf->envOffset[pt]<<(20); 243 so->targetOffset = so->wf->envOffset[pt]<<(20);
@@ -270,9 +256,14 @@ inline void stopVoice(struct SynthObject * so)
270} 256}
271 257
272 258
273inline signed short int synthVoice(void) 259signed short int synthVoice(struct SynthObject * so)
274{ 260{
275 so = &voices[currentVoice]; 261 struct GWaveform * wf;
262 register int s;
263 register unsigned int cpShifted;
264 register short s1;
265 register short s2;
266
276 wf = so->wf; 267 wf = so->wf;
277 268
278 269
@@ -288,7 +279,7 @@ inline signed short int synthVoice(void)
288 stopVoice(so); 279 stopVoice(so);
289 } 280 }
290 281
291 s2 = getSample((cpShifted)+1); 282 s2 = getSample((cpShifted)+1, wf);
292 283
293 /* LOOP_REVERSE|LOOP_PINGPONG = 24 */ 284 /* LOOP_REVERSE|LOOP_PINGPONG = 24 */
294 if((wf->mode & (24)) && so->loopState == STATE_LOOPING && (cpShifted <= (wf->startLoop))) 285 if((wf->mode & (24)) && so->loopState == STATE_LOOPING && (cpShifted <= (wf->startLoop)))
@@ -297,8 +288,9 @@ inline signed short int synthVoice(void)
297 { 288 {
298 so->cp = (wf->endLoop)<<10; //Was 10 289 so->cp = (wf->endLoop)<<10; //Was 10
299 cpShifted = wf->endLoop; 290 cpShifted = wf->endLoop;
300 s2=getSample((cpShifted)); 291 s2=getSample((cpShifted), wf);
301 } else 292 }
293 else
302 { 294 {
303 so->delta = -so->delta; 295 so->delta = -so->delta;
304 so->loopDir = LOOPDIR_FORWARD; 296 so->loopDir = LOOPDIR_FORWARD;
@@ -312,8 +304,9 @@ inline signed short int synthVoice(void)
312 { 304 {
313 so->cp = (wf->startLoop)<<10; //Was 10 305 so->cp = (wf->startLoop)<<10; //Was 10
314 cpShifted = wf->startLoop; 306 cpShifted = wf->startLoop;
315 s2=getSample((cpShifted)); 307 s2=getSample((cpShifted), wf);
316 } else 308 }
309 else
317 { 310 {
318 so->delta = -so->delta; 311 so->delta = -so->delta;
319 so->loopDir = LOOPDIR_REVERSE; 312 so->loopDir = LOOPDIR_REVERSE;
@@ -321,7 +314,7 @@ inline signed short int synthVoice(void)
321 } 314 }
322 315
323 /* Better, working, linear interpolation */ 316 /* Better, working, linear interpolation */
324 s1=getSample((cpShifted)); //\|/ Was 1023)) >> 10 317 s1=getSample((cpShifted), wf); //\|/ Was 1023)) >> 10
325 s = s1 + ((signed)((s2 - s1) * (so->cp & 1023))>>10); //Was 10 318 s = s1 + ((signed)((s2 - s1) * (so->cp & 1023))>>10); //Was 10
326 319
327 320
@@ -381,18 +374,26 @@ inline signed short int synthVoice(void)
381 374
382inline void synthSample(int * mixL, int * mixR) 375inline void synthSample(int * mixL, int * mixR)
383{ 376{
384 *mixL = 0; 377 register int dL=0;
385 *mixR = 0; 378 register int dR=0;
386 for(currentVoice=0; currentVoice<MAX_VOICES; currentVoice++) 379 register short sample=0;
380 register struct SynthObject *voicept=voices;
381 struct SynthObject *lastvoice=&voices[MAX_VOICES];
382
383 while(voicept!=lastvoice)
387 { 384 {
388 if(voices[currentVoice].isUsed==1) 385 if(voicept->isUsed==1)
389 { 386 {
390 sample = synthVoice(); 387 sample = synthVoice(voicept);
391 *mixL += (sample*chPanLeft[voices[currentVoice].ch])>>7; 388 dL += (sample*chPanLeft[voicept->ch])>>7;
392 *mixR += (sample*chPanRight[voices[currentVoice].ch])>>7; 389 dR += (sample*chPanRight[voicept->ch])>>7;
393 } 390 }
391 voicept++;
394 } 392 }
395 393
394 *mixL=dL;
395 *mixR=dR;
396
396 /* TODO: Automatic Gain Control, anyone? */ 397 /* TODO: Automatic Gain Control, anyone? */
397 /* Or, should this be implemented on the DSP's output volume instead? */ 398 /* Or, should this be implemented on the DSP's output volume instead? */
398 399
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2005 Karl Kurbjun based on midi2wav by Stepan Moskovchenko
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#include "../../plugin.h"
20
21PLUGIN_HEADER
22
23#define SAMPLE_RATE 22050 // 44100 22050 11025
24#define MAX_VOICES 12 // Note: 24 midi channels is the minimum general midi
25 // spec implementation
26#define BUF_SIZE 512
27#define NBUF 2
28
29#undef SYNC
30struct MIDIfile * mf IBSS_ATTR;
31
32int numberOfSamples IBSS_ATTR;
33long bpm IBSS_ATTR;
34
35#include "midi/midiutil.c"
36#include "midi/guspat.h"
37#include "midi/guspat.c"
38#include "midi/sequencer.c"
39#include "midi/midifile.c"
40#include "midi/synth.c"
41
42short gmbuf[BUF_SIZE*NBUF] IBSS_ATTR;
43
44int quit=0;
45struct plugin_api * rb;
46
47#ifdef USE_IRAM
48extern char iramcopy[];
49extern char iramstart[];
50extern char iramend[];
51extern char iedata[];
52extern char iend[];
53#endif
54
55enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
56{
57 rb = api;
58
59 if(parameter == NULL)
60 {
61 rb->splash(HZ*2, true, " Play .MID file ");
62 return PLUGIN_OK;
63 }
64 rb->lcd_setfont(0);
65
66#ifdef USE_IRAM
67 rb->memcpy(iramstart, iramcopy, iramend-iramstart);
68 rb->memset(iedata, 0, iend - iedata);
69#endif
70
71#if !defined(SIMULATOR) && defined(HAVE_ADJUSTABLE_CPU_FREQ)
72 rb->cpu_boost(true);
73#endif
74
75 printf("\n%s", parameter);
76/* rb->splash(HZ, true, parameter); */
77
78#ifdef RB_PROFILE
79 rb->profile_thread();
80#endif
81
82 if(midimain(parameter) == -1)
83 return PLUGIN_ERROR;
84
85#ifdef RB_PROFILE
86 rb->profstop();
87#endif
88
89#ifndef SIMULATOR
90 rb->pcm_play_stop();
91 rb->pcm_set_frequency(44100); // 44100
92#endif
93
94#if !defined(SIMULATOR) && defined(HAVE_ADJUSTABLE_CPU_FREQ)
95 rb->cpu_boost(false);
96#endif
97
98 rb->splash(HZ, true, "FINISHED PLAYING");
99
100 return PLUGIN_OK;
101}
102
103bool swap=0;
104bool lastswap=1;
105
106inline void synthbuf(void)
107{
108 short *outptr;
109 register int i;
110 static int currentSample=0;
111 int synthtemp[2];
112
113#ifndef SYNC
114 if(lastswap==swap) return;
115 lastswap=swap;
116
117 outptr=(swap ? gmbuf : gmbuf+BUF_SIZE);
118#else
119 outptr=gmbuf;
120#endif
121
122 for(i=0; i<BUF_SIZE/2; i++)
123 {
124 synthSample(&synthtemp[0], &synthtemp[1]);
125 currentSample++;
126 *outptr=synthtemp[0]&0xFFFF;
127 outptr++;
128 *outptr=synthtemp[1]&0xFFFF;
129 outptr++;
130 if(currentSample==numberOfSamples)
131 {
132 if( tick() == 0 ) quit=1;
133 currentSample=0;
134 }
135 }
136}
137
138void get_more(unsigned char** start, size_t* size)
139{
140#ifndef SYNC
141 if(lastswap!=swap)
142 {
143 printf("Buffer miss!"); // Comment out the printf to make missses less noticable.
144/*
145 int a=0;
146 for(a=0; a<MAX_VOICES; a++)
147 {
148 voices[a].isUsed=0;
149 }
150*/
151 }
152
153#else
154 synthbuf(); // For some reason midiplayer crashes when an update is forced
155#endif
156
157 *size = BUF_SIZE*sizeof(short);
158#ifndef SYNC
159 *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE));
160 swap=!swap;
161#else
162 *start = (unsigned char*)(gmbuf);
163#endif
164}
165
166int midimain(void * filename)
167{
168 int button;
169
170/* rb->splash(HZ/5, true, "LOADING MIDI"); */
171 printf("\nLoading file");
172 mf= loadFile(filename);
173
174/* rb->splash(HZ/5, true, "LOADING PATCHES"); */
175 if (initSynth(mf, "/.rockbox/patchset/patchset.cfg", "/.rockbox/patchset/drums.cfg") == -1)
176 return -1;
177
178#ifndef SIMULATOR
179 rb->pcm_play_stop();
180 rb->pcm_set_frequency(SAMPLE_RATE); // 44100 22050 11025
181#endif
182
183 /*
184 * tick() will do one MIDI clock tick. Then, there's a loop here that
185 * will generate the right number of samples per MIDI tick. The whole
186 * MIDI playback is timed in terms of this value.. there are no forced
187 * delays or anything. It just produces enough samples for each tick, and
188 * the playback of these samples is what makes the timings right.
189 *
190 * This seems to work quite well.
191 */
192
193 printf("\nOkay, starting sequencing");
194
195 bpm=mf->div*1000000/tempo;
196 numberOfSamples=SAMPLE_RATE/bpm;
197
198 tick();
199
200 synthbuf();
201#ifndef SIMULATOR
202 rb->pcm_play_data(&get_more, NULL, 0);
203#endif
204
205 button=rb->button_status();
206
207 while(!quit)
208 {
209#ifndef SYNC
210 synthbuf();
211#endif
212 rb->yield();
213 if(rb->button_status()!=button) quit=1;
214 }
215
216 return 0;
217}
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
11gb,viewers/rockboy, 0C 2A 59 7A 2E 0C 11gb,viewers/rockboy, 0C 2A 59 7A 2E 0C
12gbc,viewers/rockboy, 0C 2A 59 7A 2E 0C 12gbc,viewers/rockboy, 0C 2A 59 7A 2E 0C
13m3u,viewers/iriverify,00 00 00 00 00 00 13m3u,viewers/iriverify,00 00 00 00 00 00
14mid,viewers/midi2wav, 20 70 70 3F 00 00 14mid,viewers/midiplay, 20 70 70 3F 00 00
15rsp,viewers/searchengine, 0e 11 11 31 7e 60 15rsp,viewers/searchengine, 0e 11 11 31 7e 60
16ss,rocks/sudoku, 55 55 55 55 55 55 16ss,rocks/sudoku, 55 55 55 55 55 55
17wav,viewers/wav2wv, 00 00 00 00 00 00 17wav,viewers/wav2wv, 00 00 00 00 00 00