summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStepan Moskovchenko <stevenm@rockbox.org>2005-04-15 06:08:55 +0000
committerStepan Moskovchenko <stevenm@rockbox.org>2005-04-15 06:08:55 +0000
commit215e492a12275c8bf3399c9d40eee0dcbc7c04c0 (patch)
treee2feefec6653e12602641e85edbe396d6343f008
parent9ae63e4a3eda24c8e479ec3379a9f7074b89f686 (diff)
downloadrockbox-215e492a12275c8bf3399c9d40eee0dcbc7c04c0.tar.gz
rockbox-215e492a12275c8bf3399c9d40eee0dcbc7c04c0.zip
Added MIDI synthesizer plugin
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6287 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugins/SOURCES1
-rw-r--r--apps/plugins/midi/guspat.c151
-rw-r--r--apps/plugins/midi/guspat.h94
-rw-r--r--apps/plugins/midi/midifile.c305
-rw-r--r--apps/plugins/midi/midiutil.c262
-rw-r--r--apps/plugins/midi/sequencer.c298
-rw-r--r--apps/plugins/midi/synth.c430
-rw-r--r--apps/plugins/midi2wav.c168
8 files changed, 1709 insertions, 0 deletions
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES
index 3dd7eb473f..50b523576f 100644
--- a/apps/plugins/SOURCES
+++ b/apps/plugins/SOURCES
@@ -74,5 +74,6 @@ flac2wav.c
74vorbis2wav.c 74vorbis2wav.c
75wv2wav.c 75wv2wav.c
76mpc2wav.c 76mpc2wav.c
77midi2wav.c
77iriverify.c 78iriverify.c
78#endif 79#endif
diff --git a/apps/plugins/midi/guspat.c b/apps/plugins/midi/guspat.c
new file mode 100644
index 0000000000..f0f1effd2a
--- /dev/null
+++ b/apps/plugins/midi/guspat.c
@@ -0,0 +1,151 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2005 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
20extern struct plugin_api * rb;
21
22unsigned int readWord(int file)
23{
24 return (readChar(file)<<0) | (readChar(file)<<8); // | (readChar(file)<<8) | (readChar(file)<<0);
25}
26
27unsigned int readDWord(int file)
28{
29 return (readChar(file)<<0) | (readChar(file)<<8) | (readChar(file)<<16) | (readChar(file)<<24);
30}
31
32struct GWaveform * loadWaveform(int file)
33{
34 struct GWaveform * wav = (struct GWaveform *)allocate(sizeof(struct GWaveform));
35 rb->memset(wav, 0, sizeof(struct GWaveform));
36
37 wav->name=readData(file, 7);
38 printf("\nWAVE NAME = [%s]", wav->name);
39 wav->fractions=readChar(file);
40 wav->wavSize=readDWord(file);
41 wav->startLoop=readDWord(file);
42 wav->endLoop=readDWord(file);
43 wav->sampRate=readWord(file);
44
45 wav->lowFreq=readDWord(file);
46 wav->highFreq=readDWord(file);
47 wav->rootFreq=readDWord(file);
48
49 wav->tune=readWord(file);
50
51 wav->balance=readChar(file);
52 wav->envRate=readData(file, 6);
53 wav->envOffset=readData(file, 6);
54
55 wav->tremSweep=readChar(file);
56 wav->tremRate==readChar(file);
57 wav->tremDepth=readChar(file);
58 wav->vibSweep=readChar(file);
59 wav->vibRate=readChar(file);
60 wav->vibDepth=readChar(file);
61 wav->mode=readChar(file);
62
63 wav->scaleFreq=readWord(file);
64 wav->scaleFactor=readWord(file);
65 printf("\nScaleFreq = %d ScaleFactor = %d RootFreq = %d", wav->scaleFreq, wav->scaleFactor, wav->rootFreq);
66 wav->res=readData(file, 36);
67 wav->data=readData(file, wav->wavSize);
68
69 return wav;
70}
71
72
73
74int selectWaveform(struct GPatch * pat, int midiNote)
75{
76 int tabFreq = gustable[midiNote]/100; //Comparison
77 int a=0;
78 for(a=0; a<pat->numWaveforms; a++)
79 {
80 if(pat->waveforms[a]->lowFreq/100 <= tabFreq &&
81 pat->waveforms[a]->highFreq/100 >= tabFreq)
82 {
83 return a;
84 }
85 }
86 return 0;
87}
88
89
90struct GPatch * gusload(char * filename)
91{
92 struct GPatch * gp = (struct GPatch *)allocate(sizeof(struct GPatch));
93 rb->memset(gp, 0, sizeof(struct GPatch));
94
95 int file = rb->open(filename, O_RDONLY);
96
97 gp->header=readData(file, 12);
98 gp->gravisid=readData(file, 10);
99 gp->desc=readData(file, 60);
100 gp->inst=readChar(file);
101 gp->voc=readChar(file);
102 gp->chan=readChar(file);
103 gp->numWaveforms=readWord(file); //readWord(file);
104 gp->vol=readWord(file);
105 gp->datSize=readDWord(file);
106 gp->res=readData(file, 36);
107
108 gp->instrID=readWord(file);
109 gp->instrName=readData(file,16);
110 gp->instrSize=readDWord(file);
111 gp->layers=readChar(file);
112 gp->instrRes=readData(file,40);
113
114
115 gp->layerDup=readChar(file);
116 gp->layerID=readChar(file);
117 gp->layerSize=readDWord(file);
118 gp->numWaves=readChar(file);
119 gp->layerRes=readData(file,40);
120
121/* printf("\n%s\n%s\n%s", gp->header, gp->gravisid, gp->desc);
122 printf("\nInst = %d", gp->inst);
123 printf("\nVoc = %d", gp->voc);
124 printf("\nChan = %d", gp->chan);
125 printf("\nWav = %d", gp->numWaveforms);
126 printf("\nVol = %d", gp->vol);
127 printf("\nSize = %d", gp->datSize);
128
129 printf("\n\ninstrID = %d", gp->instrID);
130 printf("\ninstrName = %s", gp->instrName);
131// printf("\ninstrSize = %d", gp->instrSize);
132// printf("\nlayers = %d", gp->layers);
133*/
134 printf("\nFILE: %s", filename);
135 printf("\nlayerSamples=%d", gp->numWaves);
136
137 int a=0;
138 for(a=0; a<gp->numWaves; a++)
139 gp->waveforms[a] = loadWaveform(file);
140
141
142 printf("\nPrecomputing note table");
143
144 for(a=0; a<128; a++)
145 {
146 gp->noteTable[a] = selectWaveform(gp, a);
147 }
148 rb->close(file);
149
150 return gp;
151}
diff --git a/apps/plugins/midi/guspat.h b/apps/plugins/midi/guspat.h
new file mode 100644
index 0000000000..5007c4d2ca
--- /dev/null
+++ b/apps/plugins/midi/guspat.h
@@ -0,0 +1,94 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2005 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//This came from one of the Gravis documents
20const static unsigned int gustable[]=
21{
22 8175, 8661, 9177, 9722, 10300, 10913, 11562, 12249, 12978, 13750, 14567, 15433,
23 16351, 17323, 18354, 19445, 20601, 21826, 23124, 24499, 25956, 27500, 29135, 30867,
24 32703, 34647, 36708, 38890, 41203, 43653, 46249, 48999, 51913, 54999, 58270, 61735,
25 65406, 69295, 73416, 77781, 82406, 87306, 92498, 97998, 103826, 109999, 116540, 123470,
26 130812, 138591, 146832, 155563, 164813, 174614, 184997, 195997, 207652, 219999, 233081, 246941,
27 261625, 277182, 293664, 311126, 329627, 349228, 369994, 391995, 415304, 440000, 466163, 493883,
28 523251, 554365, 587329, 622254, 659255, 698456, 739989, 783991, 830609, 880000, 932328, 987767,
29 1046503, 1108731, 1174660, 1244509, 1318511, 1396914, 1479979, 1567983, 1661220, 1760002, 1864657, 1975536,
30 2093007, 2217464, 2349321, 2489019, 2637024, 2793830, 2959960, 3135968, 3322443, 3520006, 3729316, 3951073,
31 4186073, 4434930, 4698645, 4978041, 5274051, 5587663, 5919922, 6271939, 6644889, 7040015, 7458636, 7902150
32};
33
34struct GWaveform
35{
36 unsigned char * name;
37 unsigned char fractions;
38 unsigned int wavSize;
39 unsigned int startLoop;
40 unsigned int endLoop;
41 unsigned int sampRate;
42 unsigned int lowFreq;
43 unsigned int highFreq;
44 unsigned int rootFreq;
45 unsigned int tune;
46 unsigned int balance;
47 unsigned char * envRate;
48 unsigned char * envOffset;
49
50 unsigned char tremSweep;
51 unsigned char tremRate;
52 unsigned char tremDepth;
53 unsigned char vibSweep;
54 unsigned char vibRate;
55 unsigned char vibDepth;
56 unsigned char mode;
57
58 unsigned int scaleFreq;
59 unsigned int scaleFactor;
60
61 unsigned char * res;
62 signed char * data;
63};
64
65
66struct GPatch
67{
68 unsigned int patchNumber;
69 unsigned char * header;
70 unsigned char * gravisid;
71 unsigned char * desc;
72 unsigned char inst, voc, chan;
73 unsigned int numWaveforms;
74 unsigned int datSize;
75 unsigned int vol;
76 unsigned char * res;
77
78
79 unsigned int instrID;
80 unsigned char * instrName;
81 unsigned int instrSize;
82 unsigned int layers;
83 unsigned char * instrRes;
84
85 unsigned char layerDup;
86 unsigned char layerID;
87 unsigned int layerSize;
88 unsigned char numWaves;
89 unsigned char * layerRes;
90
91 unsigned char noteTable[128];
92 struct GWaveform * waveforms[255];
93};
94
diff --git a/apps/plugins/midi/midifile.c b/apps/plugins/midi/midifile.c
new file mode 100644
index 0000000000..08efb73529
--- /dev/null
+++ b/apps/plugins/midi/midifile.c
@@ -0,0 +1,305 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2005 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
20
21extern struct plugin_api * rb;
22
23struct Track * readTrack(int file);
24int readID(int file);
25void bail(const char *);
26
27struct MIDIfile * loadFile(char * filename)
28{
29 struct MIDIfile * mf;
30 int file = rb->open (filename, O_RDONLY);
31
32 if(file==0)
33 {
34 bail("Could not open file\n");
35 }
36
37 mf = (struct MIDIfile*)allocate(sizeof(struct MIDIfile));
38
39 if(mf==NULL)
40 {
41 rb->close(file);
42 bail("Could not allocate memory for MIDIfile struct\n");
43 }
44
45 rb->memset(mf, 0, sizeof(struct MIDIfile));
46
47 if(readID(file) != ID_MTHD)
48 {
49 rb->close(file);
50 bail("Invalid file header chunk.");
51 }
52
53 if(readFourBytes(file)!=6)
54 {
55 rb->close(file);
56 bail("Header chunk size invalid.");
57 }
58
59 if(readTwoBytes(file)==2)
60 {
61 rb->close(file);
62 bail("MIDI file type not supported");
63 }
64
65 mf->numTracks = readTwoBytes(file);
66 mf->div = readTwoBytes(file);
67
68 int track=0;
69
70 printf("\nnumTracks=%d div=%d\nBegin reading track data\n", mf->numTracks, mf->div);
71
72// return;
73
74
75 while(! eof(file) && track < mf->numTracks)
76 {
77 unsigned char id = readID(file);
78
79
80 if(id == ID_EOF)
81 {
82 if(mf->numTracks != track)
83 {
84 printf("\nError: file claims to have %d tracks.\n I only see %d here.\n", mf->numTracks, track);
85 mf->numTracks = track;
86 }
87 return mf;
88 }
89
90 if(id == ID_MTRK)
91 {
92 mf->tracks[track] = readTrack(file);
93 //exit(0);
94 track++;
95 } else
96 {
97 printf("\n SKIPPING TRACK");
98 int len = readFourBytes(file);
99 while(--len)
100 readChar(file);
101 }
102 }
103 return mf;
104
105}
106
107
108int rStatus = 0;
109
110//Returns 0 if done, 1 if keep going
111int readEvent(int file, void * dest)
112{
113 struct Event dummy;
114 struct Event * ev = (struct Event *) dest;
115
116 if(ev == NULL)
117 ev = &dummy; //If we are just counting events instead of loading them
118
119 ev->delta = readVarData(file);
120
121
122 int t=readChar(file);
123
124 if((t&0x80) == 0x80) //if not a running status event
125 {
126 ev->status = t;
127 if(t == 0xFF)
128 {
129 ev->d1 = readChar(file);
130 ev->len = readVarData(file);
131
132 //Allocate and read in the data block
133 if(dest != NULL)
134 {
135 ev->evData = readData(file, ev->len);
136 printf("\nDATA: <%s>", ev->evData);
137 }
138 else
139 {
140 //Don't allocate anything, just see how much it would tale
141 //To make memory usage efficient
142
143 int a=0;
144 for(a=0; a<ev->len; a++)
145 readChar(file); //Skip skip
146 }
147
148 if(ev->d1 == 0x2F)
149 {
150 return 0; //Termination meta-event
151 }
152 } else //If part of a running status event
153 {
154 rStatus = t;
155 ev->status = t;
156 ev->d1 = readChar(file);
157
158 if ( ((t & 0xF0) != 0xD0) && ((t & 0xF0) != 0xC0) && ((t & 0xF0) > 0x40) )
159 {
160 ev->d2 = readChar(file);
161 } else
162 ev->d2 = 127;
163 }
164 } else //Running Status
165 {
166 ev->status = rStatus;
167 ev->d1 = t;
168 if ( ((rStatus & 0xF0) != 0xD0) && ((rStatus & 0xF0) != 0xC0) && ((rStatus & 0xF0) > 0x40) )
169 {
170 ev->d2 = readChar(file);
171 } else
172 ev->d2 = 127;
173 }
174 return 1;
175}
176
177
178
179struct Track * readTrack(int file)
180{
181 struct Track * trk = (struct Track *)allocate(sizeof(struct Track));
182 rb->memset(trk, 0, sizeof(struct Track));
183
184 trk->size = readFourBytes(file);
185 trk->pos = 0;
186 trk->delta = 0;
187
188 int len=0;
189 int numEvents=0;
190
191 int pos = rb->lseek(file, 0, SEEK_CUR);
192
193 while(readEvent(file, NULL)) //Memory saving technique
194 numEvents++; //Attempt to read in events, count how many
195 //THEN allocate memory and read them in
196 rb->lseek(file, pos, SEEK_SET);
197
198 int trackSize = (numEvents+1) * sizeof(struct Event);
199 void * dataPtr = allocate(trackSize);
200 trk->dataBlock = dataPtr;
201
202 numEvents=0;
203
204 while(readEvent(file, dataPtr))
205 {
206 if(trackSize < dataPtr-trk->dataBlock)
207 {
208 printf("\nTrack parser memory out of bounds");
209 exit(1);
210 }
211 dataPtr+=sizeof(struct Event);
212 numEvents++;
213 }
214 trk->numEvents = numEvents;
215
216 return trk;
217}
218
219
220int readID(int file)
221{
222 char id[5];
223 id[4]=0;
224 BYTE a;
225
226 for(a=0; a<4; a++)
227 id[a]=readChar(file);
228 if(eof(file))
229 {
230 printf("\End of file reached.");
231 return ID_EOF;
232 }
233 if(rb->strcmp(id, "MThd")==0)
234 return ID_MTHD;
235 if(rb->strcmp(id, "MTrk")==0)
236 return ID_MTRK;
237 return ID_UNKNOWN;
238}
239
240
241int readFourBytes(int file)
242{
243 int data=0;
244 BYTE a=0;
245 for(a=0; a<4; a++)
246 data=(data<<8)+readChar(file);
247 return data;
248}
249
250int readTwoBytes(int file)
251{
252 int data=(readChar(file)<<8)+readChar(file);
253 return data;
254}
255
256//This came from the MIDI file format guide
257int readVarData(int file)
258{
259 unsigned int value;
260 char c;
261 if ( (value = readChar(file)) & 0x80 )
262 {
263 value &= 0x7F;
264 do
265 {
266 value = (value << 7) + ((c = readChar(file)) & 0x7F);
267 } while (c & 0x80);
268 }
269 return(value);
270}
271
272//This function should not be needed because we
273//can just release the whole memory buffer at once
274void unloadFile(struct MIDIfile * mf)
275{
276 if(mf == NULL)
277 return;
278 int a=0;
279 //Unload each track
280 for(a=0; a<mf->numTracks; a++)
281 {
282 int b=0;
283
284 if(mf->tracks[a] != NULL)
285 for(b=0; b<mf->tracks[a]->numEvents; b++)
286 {
287 if(((struct Event*)((mf->tracks[a]->dataBlock)+b*sizeof(struct Event)))->evData!=NULL)
288 free(((struct Event*)((mf->tracks[a]->dataBlock)+b*sizeof(struct Event)))->evData);
289 }
290
291 if(mf->tracks[a]!=NULL && mf->tracks[a]->dataBlock != NULL)
292 free(mf->tracks[a]->dataBlock); //Unload the event block
293
294 if(mf->tracks[a]!=NULL)
295 free(mf->tracks[a]); //Unload the track structure itself
296 }
297 free(mf); //Unload the main struct
298}
299
300void bail(const char * err)
301{
302 printf("\nERROR: %s\n", err);
303 exit(0);
304}
305
diff --git a/apps/plugins/midi/midiutil.c b/apps/plugins/midi/midiutil.c
new file mode 100644
index 0000000000..0ab5a35a78
--- /dev/null
+++ b/apps/plugins/midi/midiutil.c
@@ -0,0 +1,262 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2005 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
20#define BYTE unsigned char
21
22//Data chunk ID types, returned by readID()
23#define ID_UNKNOWN -1
24#define ID_MTHD 1
25#define ID_MTRK 2
26#define ID_EOF 3
27
28//MIDI Commands
29#define MIDI_NOTE_OFF 128
30#define MIDI_NOTE_ON 144
31#define MIDI_AFTERTOUCH 160
32#define MIDI_CONTROL 176
33#define MIDI_PRGM 192
34#define MIDI_PITCHW 224
35
36
37//MIDI Controllers
38#define CTRL_VOLUME 7
39#define CTRL_BALANCE 8
40#define CTRL_PANNING 10
41#define CHANNEL 1
42
43
44#define STATE_ATTACK 1
45#define STATE_DECAY 2
46#define STATE_SUSTAIN 3
47#define STATE_RELEASE 4
48#define STATE_RAMPDOWN 5
49
50#define STATE_LOOPING 7
51#define STATE_NONLOOPING 8
52
53#define LOOP_ENABLED 4
54#define LOOP_PINGPONG 8
55#define LOOP_REVERSE 16
56
57#define LOOPDIR_FORWARD 0
58#define LOOPDIR_REVERSE 1
59
60
61extern struct plugin_api * rb;
62
63
64unsigned char chVol[16]; //Channel volume
65unsigned char chPanLeft[16]; //Channel panning
66unsigned char chPanRight[16];
67unsigned char chPat[16]; //Channel patch
68unsigned char chPW[16]; //Channel pitch wheel, MSB
69
70struct GPatch * gusload(char *);
71struct GPatch * patchSet[128];
72struct GPatch * drumSet[128];
73struct SynthObject voices[MAX_VOICES];
74
75
76
77struct SynthObject
78{
79 int tmp;
80 struct GWaveform * wf;
81 unsigned int delta;
82 unsigned int decay;
83 unsigned int cp;
84 unsigned char state, pstate, loopState, loopDir;
85 unsigned char note, vol, ch, isUsed;
86 int curRate, curOffset, targetOffset;
87 int curPoint;
88};
89
90
91struct Event
92{
93 unsigned int delta;
94 unsigned char status, d1, d2;
95 unsigned int len;
96 unsigned char * evData;
97};
98
99struct Track
100{
101 unsigned int size;
102 unsigned int numEvents;
103 unsigned int delta; //For sequencing
104 unsigned int pos; //For sequencing
105 void * dataBlock;
106};
107
108
109struct MIDIfile
110{
111 int Length;
112
113 //int Format; //We don't really care what type it is
114 unsigned short numTracks;
115 unsigned short div; //Time division, X ticks per millisecond
116 struct Track * tracks[48];
117 unsigned char patches[128];
118 int numPatches;
119};
120
121void *my_malloc(int size);
122
123void *alloc(int size)
124{
125 static char *offset = NULL;
126 static int totalSize = 0;
127 char *ret;
128
129 if (offset == NULL)
130 {
131 offset = rb->plugin_get_audio_buffer(&totalSize);
132 }
133
134 if (size + 4 > totalSize)
135 {
136 return NULL;
137 }
138
139 ret = offset + 4;
140 *((unsigned int *)offset) = size;
141
142 offset += size + 4;
143 totalSize -= size + 4;
144 return ret;
145}
146
147void *ralloc(char *offset, int len)
148{
149 int size;
150 char *ret;
151
152 if (offset == NULL)
153 {
154 return alloc(len);
155 }
156
157 size = *((unsigned int *)offset - 4);
158
159 if (size >= 0x02000000)
160 {
161 return NULL;
162 }
163
164 ret = alloc(len);
165
166 if (len < size)
167 {
168 rb->memcpy(ret, offset, len);
169 }
170 else
171 {
172 rb->memcpy(ret, offset, size);
173 rb->memset(ret, 0, len - size);
174 }
175
176 return ret;
177}
178
179
180void * allocate(int size)
181{
182 return alloc(size);
183}
184
185void sendEvent(struct Event * ev);
186int tick(struct MIDIfile * mf);
187inline void setPoint(struct SynthObject * so, int pt);
188struct Event * getEvent(struct Track * tr, int evNum);
189
190unsigned char readChar(int file)
191{
192 char buf[2];
193 rb->read(file, &buf, 1);
194 return buf[0];
195}
196
197unsigned char * readData(int file, int len)
198{
199 unsigned char * dat = allocate(len);
200 rb->read(file, dat, len);
201 return dat;
202}
203
204int eof(int fd)
205{
206 int curPos = rb->lseek(fd, 0, SEEK_CUR);
207
208 int size = rb->lseek(fd, 0, SEEK_END);
209
210 rb->lseek(fd, curPos, SEEK_SET);
211 return size+1 == rb->lseek(fd, 0, SEEK_CUR);
212}
213
214void printf(char *fmt, ...) {}
215
216//#define my_malloc(a) malloc(a)
217
218
219void *audio_bufferbase;
220void *audio_bufferpointer;
221unsigned int audio_buffer_free;
222
223
224
225
226void *my_malloc(int size)
227{
228
229 void *alloc;
230
231 if (!audio_bufferbase)
232 {
233 audio_bufferbase = audio_bufferpointer
234 = rb->plugin_get_audio_buffer(&audio_buffer_free);
235#if MEM <= 8 && !defined(SIMULATOR)
236
237 if ((unsigned)(ovl_start_addr - (unsigned char *)audio_bufferbase)
238 < audio_buffer_free)
239 audio_buffer_free = ovl_start_addr - (unsigned char *)audio_bufferbase;
240#endif
241 }
242 if (size + 4 > audio_buffer_free)
243 return 0;
244 alloc = audio_bufferpointer;
245 audio_bufferpointer += size + 4;
246 audio_buffer_free -= size + 4;
247 return alloc;
248}
249
250void setmallocpos(void *pointer)
251{
252 audio_bufferpointer = pointer;
253 audio_buffer_free = audio_bufferpointer - audio_bufferbase;
254}
255
256void exit(int code)
257{
258}
259
260void free(void * ptr)
261{
262} \ No newline at end of file
diff --git a/apps/plugins/midi/sequencer.c b/apps/plugins/midi/sequencer.c
new file mode 100644
index 0000000000..fb98fdaf51
--- /dev/null
+++ b/apps/plugins/midi/sequencer.c
@@ -0,0 +1,298 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2005 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
20extern struct plugin_api * rb;
21
22long tempo=375000;
23
24
25void setVol(int ch, int vol)
26{
27 printf("\nvolume[%d] %d ==> %d", ch, chVol[ch], vol);
28 chVol[ch]=vol;
29}
30
31void setPan(int ch, int pan)
32{
33 printf("\npanning[%d] %d ==> %d", ch, chPanRight[ch], pan);
34
35 chPanLeft[ch]=128-pan;
36 chPanRight[ch]=pan;
37}
38
39
40void setPatch(int ch, int pat)
41{
42 chPat[ch]=pat;
43}
44
45
46/*
47 Pitch Bend table, Computed by
48 for i=0:127, fprintf('%d,', round(2^16*2^((i-64)/384))); end
49 (When typed into Matlab)
50 16 bit pitch bend table
51*/
52long pitchTbl[]=
53{
54 58386,58491,58597,58703,58809,58915,59022,59128,59235,59342,59449,59557,59664,59772,59880,59988,60097,60205,
55 60314,60423,60532,60642,60751,60861,60971,61081,61191,61302,61413,61524,61635,61746,61858,61970,62081,62194,
56 62306,62419,62531,62644,62757,62871,62984,63098,63212,63326,63441,63555,63670,63785,63901,64016,64132,64248,
57 64364,64480,64596,64713,64830,64947,65065,65182,65300,65418,65536,65654,65773,65892,66011,66130,66250,66369,
58 66489,66609,66730,66850,66971,67092,67213,67335,67456,67578,67700,67823,67945,68068,68191,68314,68438,68561,
59 68685,68809,68933,69058,69183,69308,69433,69558,69684,69810,69936,70062,70189,70316,70443,70570,70698,70825,
60 70953,71082,71210,71339,71468,71597,71726,71856,71985,72115,72246,72376,72507,72638,72769,72901,73032,73164,
61 73297,73429
62};
63
64
65void findDelta(struct SynthObject * so, int ch, int note)
66{
67
68 struct GWaveform * wf = patchSet[chPat[ch]]->waveforms[patchSet[chPat[ch]]->noteTable[note]];
69 so->wf=wf;
70 so->delta = (((gustable[note]<<10) / wf->rootFreq) * wf->sampRate / SAMPLE_RATE);
71 so->delta = so->delta * pitchTbl[chPW[ch]] >> 16;
72}
73
74void setPW(int ch, int msb)
75{
76 printf("\npitchw[%d] %d ==> %d", ch, chPW[ch], msb);
77 chPW[ch] = msb;
78
79 int a=0;
80 for(a = 0; a<MAX_VOICES; a++)
81 {
82 if(voices[a].isUsed==1 && voices[a].ch == ch)
83 {
84 findDelta(&voices[a], ch, voices[a].note);
85 }
86 }
87}
88
89void pressNote(int ch, int note, int vol)
90{
91 int a=0;
92 for(a=0; a<MAX_VOICES; a++)
93 {
94 if(voices[a].isUsed==0)
95 break;
96 }
97 if(a==MAX_VOICES-1)
98 {
99 printf("\nOVERFLOW: Too many voices playing at once. No more left");
100 printf("\nVOICE DUMP: ");
101 for(a=0; a<48; a++)
102 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);
103 return; //None avaolable
104 }
105 voices[a].ch=ch;
106 voices[a].note=note;
107 voices[a].vol=vol;
108 voices[a].cp=0;
109 voices[a].state=STATE_ATTACK;
110 voices[a].pstate=STATE_ATTACK;
111 voices[a].decay=255;
112
113
114 voices[a].loopState=STATE_NONLOOPING;
115 voices[a].loopDir = LOOPDIR_FORWARD;
116 /*
117 OKAY. Gt = Gus Table value
118 rf = Root Frequency of wave
119 SR = sound sampling rate
120 sr = WAVE sampling rate
121 */
122
123
124 /*
125 unsigned int gt = gustable[note];
126 unsigned int rf = wf->rootFreq;
127 unsigned int SR = SAMPLE_RATE;
128 unsigned int sr = wf->sampRate;
129 voices[a].delta=((((gt<<10) / rf) * sr / SR));
130 */
131
132
133 if(ch!=9)
134 {
135 findDelta(&voices[a], ch, note);
136 //Turn it on
137 voices[a].isUsed=1;
138 setPoint(&voices[a], 0);
139 } else
140 {
141 if(drumSet[note]!=NULL)
142 {
143 if(note<35)
144 printf("\nNOTE LESS THAN 35, AND A DRUM PATCH EXISTS FOR THIS? WHAT THE HELL?");
145
146 struct GWaveform * wf = drumSet[note]->waveforms[0];
147 voices[a].wf=wf;
148 voices[a].delta = (((gustable[note]<<10) / wf->rootFreq) * wf->sampRate / SAMPLE_RATE);
149 if(wf->mode & 28)
150 printf("\nWoah, a drum patch has a loop. Stripping the loop...");
151 wf->mode = wf->mode & (255-28);
152 //Turn it on
153 voices[a].isUsed=1;
154 setPoint(&voices[a], 0);
155
156 } else
157 {
158 printf("\nWarning: drum %d does not have a patch defined... Ignoring it", note);
159 }
160 }
161}
162
163
164void releaseNote(int ch, int note)
165{
166 if(ch==9) // && note != 27 && note != 31 && note != 28)
167 return;
168 int a=0;
169 for(a=0; a<MAX_VOICES; a++)
170 {
171 if(voices[a].ch == ch && voices[a].note == note)
172 {
173 //voices[a].isUsed=0;
174 if((voices[a].wf->mode & 28))
175 {
176 voices[a].tmp=40;
177// voices[a].state = STATE_RELEASE; //Ramp down
178
179// voices[a].state = STATE_RAMPDOWN; //Ramp down
180
181// voices[a].isUsed = 0;
182 setPoint(&voices[a], 3);
183 }
184 }
185 }
186}
187
188void sendEvent(struct Event * ev)
189{
190// printf("\nEVENT S=%2x D1=%2x D2=%2x", ev->status, ev->d1, ev->d2);
191
192 if( ((ev->status & 0xF0) == MIDI_CONTROL) && (ev->d1 == CTRL_VOLUME) )
193 {
194 setVol((ev->status & 0xF), ev->d2);
195 return;
196 }
197
198 if( ((ev->status & 0xF0) == MIDI_CONTROL) && (ev->d1 == CTRL_PANNING))
199 {
200 setPan((ev->status & 0xF), ev->d2);
201 return;
202 }
203
204 if(((ev->status & 0xF0) == MIDI_PITCHW))
205 {
206 setPW((ev->status & 0xF), ev->d2);
207 return;
208 }
209
210 if(((ev->status & 0xF0) == MIDI_NOTE_ON) && (ev->d2 != 0))
211 {
212 pressNote(ev->status & 0x0F, ev->d1, ev->d2);
213 return;
214 }
215
216 if(((ev->status & 0xF0) == MIDI_NOTE_ON) && (ev->d2 == 0)) //Release by vol=0
217 {
218 releaseNote(ev->status & 0x0F, ev->d1);
219 return;
220 }
221
222
223 if((ev->status & 0xF0) == MIDI_NOTE_OFF)
224 {
225 releaseNote(ev->status & 0x0F, ev->d1);
226 return;
227 }
228
229 if((ev->status & 0xF0) == MIDI_PRGM)
230 {
231 if((ev->status & 0x0F) == 9)
232 printf("\nNOT PATCHING: Someone tried patching Channel 9 onto something?");
233 else
234 setPatch(ev->status & 0x0F, ev->d1);
235 }
236}
237
238
239
240
241
242int tick(struct MIDIfile * mf)
243{
244 if(mf==NULL)
245 return;
246
247 int a=0;
248 int tracksAdv=0;
249 for(a=0; a<mf->numTracks; a++)
250 {
251 struct Track * tr = mf->tracks[a];
252
253 if(tr == NULL)
254 printf("\nNULL TRACK: %d", a);
255
256
257 //BIG DEBUG STATEMENT
258 //printf("\nTrack %2d, Event = %4d of %4d, Delta = %5d, Next = %4d", a, tr->pos, tr->numEvents, tr->delta, getEvent(tr, tr->pos)->delta);
259
260
261 if(tr != NULL && (tr->pos < tr->numEvents))
262 {
263 tr->delta++;
264 tracksAdv++;
265 while(getEvent(tr, tr->pos)->delta <= tr->delta)
266 {
267// printf("\nDelta = %d", tr->delta);
268 struct Event * e = getEvent(tr, tr->pos);
269
270 if(e->status != 0xFF)
271 {
272 sendEvent(e);
273 if(((e->status&0xF0) == MIDI_PRGM))
274 {
275 printf("\nPatch Event, patch[%d] ==> %d", e->status&0xF, e->d1);
276 }
277 }
278 else
279 {
280 if(e->d1 == 0x51)
281 {
282 tempo = (((short)e->evData[0])<<16)|(((short)e->evData[1])<<8)|(e->evData[2]);
283 printf("\nMeta-Event: Tempo Set = %d", tempo);
284 }
285 }
286 tr->delta = 0;
287 tr->pos++;
288 if(tr->pos>=(tr->numEvents-1))
289 break;
290 }
291 }
292 }
293
294 if(tracksAdv != 0)
295 return 1;
296 else
297 return 0;
298}
diff --git a/apps/plugins/midi/synth.c b/apps/plugins/midi/synth.c
new file mode 100644
index 0000000000..0d07ed91d0
--- /dev/null
+++ b/apps/plugins/midi/synth.c
@@ -0,0 +1,430 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2005 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
20
21extern struct plugin_api * rb;
22
23struct Event * getEvent(struct Track * tr, int evNum)
24{
25 return tr->dataBlock + (evNum*sizeof(struct Event));
26}
27
28void readTextBlock(int file, char * buf)
29{
30 char c = 0;
31 do
32 {
33 c = readChar(file);
34 } while(c == '\n' || c == ' ' || c=='\t');
35
36 rb->lseek(file, -1, SEEK_CUR);
37 int cp = 0;
38 do
39 {
40 c = readChar(file);
41 buf[cp] = c;
42 cp++;
43 } while (c != '\n' && c != ' ' && c != '\t' && !eof(file));
44 buf[cp-1]=0;
45 rb->lseek(file, -1, SEEK_CUR);
46}
47
48
49
50//Filename is the name of the config file
51//The MIDI file should have been loaded at this point
52void initSynth(struct MIDIfile * mf, char * filename, char * drumConfig)
53{
54 char patchUsed[128];
55 char drumUsed[128];
56 int a=0;
57 for(a=0; a<MAX_VOICES; a++)
58 {
59 voices[a].cp=0;
60 voices[a].vol=0;
61 voices[a].ch=0;
62 voices[a].isUsed=0;
63 voices[a].note=0;
64 }
65
66 for(a=0; a<16; a++)
67 {
68 chVol[a]=100; //Default, not quite full blast..
69 chPanLeft[a]=64; //Center
70 chPanRight[a]=64; //Center
71 chPat[a]=0; //Ac Gr Piano
72 chPW[a]=64; // .. not .. bent ?
73 }
74 for(a=0; a<128; a++)
75 {
76 patchSet[a]=NULL;
77 drumSet[a]=NULL;
78 patchUsed[a]=0;
79 drumUsed[a]=0;
80 }
81
82 //Always load the piano.
83 //Some files will assume its loaded without specifically
84 //issuing a Patch command... then we wonder why we can't hear anything
85 patchUsed[0]=1;
86
87 //Scan the file to see what needs to be loaded
88 for(a=0; a<mf->numTracks; a++)
89 {
90 int ts=0;
91
92 if(mf->tracks[a] == NULL)
93 {
94 printf("\nNULL TRACK !!!");
95 exit(1);
96 return;
97 }
98
99 for(ts=0; ts<mf->tracks[a]->numEvents; ts++)
100 {
101
102 if((getEvent(mf->tracks[a], ts)->status) == (MIDI_NOTE_ON+9))
103 drumUsed[getEvent(mf->tracks[a], ts)->d1]=1;
104
105 if( (getEvent(mf->tracks[a], ts)->status & 0xF0) == MIDI_PRGM)
106 {
107 if(patchUsed[getEvent(mf->tracks[a], ts)->d1]==0)
108 printf("\nI need to load patch %d.", getEvent(mf->tracks[a], ts)->d1);
109 patchUsed[getEvent(mf->tracks[a], ts)->d1]=1;
110 }
111 }
112 }
113
114 int file = rb->open(filename, O_RDONLY);
115
116 char name[30];
117 char fn[30];
118
119 //Scan our config file and load the right patches as needed
120 int c = 0;
121 rb->snprintf(name, 30, "");
122 for(a=0; a<128; a++)
123 {
124 while(readChar(file)!=' ' && !eof(file));
125 readTextBlock(file, name);
126
127 rb->snprintf(fn, 30, "/patchset/%s.pat", name);
128 printf("\nLOADING: <%s> ", fn);
129 if(patchUsed[a]==1)
130 patchSet[a]=gusload(fn);
131
132 while((c != '\n'))
133 c = readChar(file);
134 }
135 rb->close(file);
136
137 file = rb->open(drumConfig, O_RDONLY);
138
139 //Scan our config file and load the drum data
140 int idx=0;
141 char number[30];
142 while(!eof(file))
143 {
144 readTextBlock(file, number);
145 readTextBlock(file, name);
146 rb->snprintf(fn, 30, "/patchset/%s.pat", name);
147
148 idx = rb->atoi(number);
149 if(idx == 0)
150 break;
151
152 if(drumUsed[idx]==1)
153 drumSet[idx]=gusload(fn);
154 while((c != '\n') && (c != 255) && (!eof(file)))
155 {
156 printf("loop");
157 c = readChar(file);
158 }
159 }
160 rb->close(file);
161}
162
163
164
165inline signed short int getSample(struct GWaveform * wf, unsigned int s)
166{
167
168 //16 bit samples
169 if(wf->mode&1)
170 {
171
172 if(s<<1 >= wf->wavSize)
173 {
174 // printf("\nSAMPLE OUT OF RANGE: s=%d 2s=%d ws=%d", s, 2*s, wf->wavSize);
175 return 0;
176 }
177
178
179 /*
180 * Probably put the signed/unsigned and and 8-16 bit conversion
181 * into the patch loader and have it run there, once.
182 */
183
184
185 //If they are unsigned, convert them to signed
186 //or was it the other way around. Whatever, it works
187 unsigned char b1=wf->data[s<<1]+((wf->mode & 2) << 6);
188 unsigned char b2=wf->data[(s<<1)|1]+((wf->mode & 2) << 6);
189 return (b1 | (b2<<8));
190 }
191 else
192 { //8-bit samples
193 unsigned char b1=wf->data[s]+((wf->mode & 2) << 6);
194 return b1<<8;
195 }
196}
197
198
199
200
201inline void setPoint(struct SynthObject * so, int pt)
202{
203 if(so->ch==9) //Drums, no ADSR
204 {
205 so->curOffset = 1<<27;
206 so->curRate = 1;
207 return;
208 }
209
210 if(so->wf==NULL)
211 {
212 printf("\nCrap... null waveform...");
213 exit(1);
214 }
215 if(so->wf->envRate==NULL)
216 {
217 printf("\nWaveform has no envelope set");
218 exit(1);
219 }
220
221 so->curPoint = pt;
222
223 int r=0;
224
225
226
227
228 int rate = so->wf->envRate[pt];
229
230 r=3-((rate>>6) & 0x3); // Some blatant Timidity code for rate conversion...
231 r*=3;
232 r = (rate & 0x3f) << r;
233
234 /*
235 Okay. This is the rate shift. Timidity defaults to 9, and sets
236 it to 10 if you use the fast decay option. Slow decay sounds better
237 on some files, except on some other files... you get chords that aren't
238 done decaying yet.. and they dont harmonize with the next chord and it
239 sounds like utter crap. Yes, even Timitidy does that. So I'm going to
240 default this to 10, and maybe later have an option to set it to 9
241 for longer decays.
242 */
243 so->curRate = r<<9;
244
245
246 so->targetOffset = so->wf->envOffset[pt]<<(20);
247 if(pt==0)
248 so->curOffset = 0;
249}
250
251
252long msi=0;
253
254inline void stopVoice(struct SynthObject * so)
255{
256 if(so->state == STATE_RAMPDOWN)
257 return;
258 so->state = STATE_RAMPDOWN;
259 so->decay = 255;
260
261}
262
263int rampDown = 0;
264
265inline signed short int synthVoice(int v)
266{
267 //Probably can combine these 2 lines into one..
268 //But for now, this looks more readable
269// struct GPatch * pat = patchSet[chPat[voices[v].ch]];
270// struct GWaveform * wf = pat->waveforms[pat->noteTable[voices[v].note]];
271 struct SynthObject * so = &voices[v];
272 struct GWaveform * wf = so->wf;
273
274 signed int s;
275
276 if(so->state != STATE_RAMPDOWN)
277 {
278 if(so->loopDir==LOOPDIR_FORWARD)
279 {
280 so->cp += so->delta;
281 }
282 else
283 {
284 so->cp -= so->delta;
285 }
286 }
287
288 if( (so->cp>>9 >= (wf->wavSize)) && (so->state != STATE_RAMPDOWN))
289 stopVoice(so);
290
291 /*
292 //Original, working, no interpolation
293 s=getSample(wf, (so->cp>>10));
294 */
295
296
297
298 int s2=getSample(wf, (so->cp>>10)+1);
299
300 if((wf->mode & (LOOP_REVERSE|LOOP_PINGPONG)) && so->loopState == STATE_LOOPING && (so->cp>>10 <= (wf->startLoop>>1)))
301 {
302 if(wf->mode & LOOP_REVERSE)
303 {
304 so->cp = (wf->endLoop)<<9;
305 s2=getSample(wf, (so->cp>>10));
306 } else
307 so->loopDir = LOOPDIR_FORWARD;
308 }
309
310 if((wf->mode & 28) && (so->cp>>10 >= wf->endLoop>>1))
311 {
312 so->loopState = STATE_LOOPING;
313 if((wf->mode & (24)) == 0)
314 {
315 so->cp = (wf->startLoop)<<9;
316 s2=getSample(wf, (so->cp>>10));
317 } else
318 so->loopDir = LOOPDIR_REVERSE;
319 }
320
321 //Better, working, linear interpolation
322 int s1=getSample(wf, (so->cp>>10));
323 s = s1 + ((long)((s2 - s1) * (so->cp & 1023))>>10);
324
325 if(so->curRate == 0)
326 stopVoice(so);
327
328
329 if(so->ch != 9) //Stupid ADSR code... and don't do ADSR for drums
330 {
331 if(so->curOffset < so->targetOffset)
332 {
333 so->curOffset += (so->curRate);
334 if(so -> curOffset > so->targetOffset && so->curPoint != 2)
335 {
336 if(so->curPoint != 5)
337 setPoint(so, so->curPoint+1);
338 else
339 stopVoice(so);
340 }
341 } else
342 {
343 so->curOffset -= (so->curRate);
344 if(so -> curOffset < so->targetOffset && so->curPoint != 2)
345 {
346
347 if(so->curPoint != 5)
348 setPoint(so, so->curPoint+1);
349 else
350 stopVoice(so);
351
352 }
353 }
354 }
355
356 if(so->curOffset < 0)
357 so->isUsed=0; //This is OK
358
359 s = s * (so->curOffset >> 22);
360 s = s>>6;
361
362
363 if(so->state == STATE_RAMPDOWN)
364 {
365 so->decay--;
366 if(so->decay == 0)
367 so->isUsed=0;
368 }
369
370 s = s * so->decay; s = s >> 9;
371
372 return s*((signed short int)so->vol*(signed short int)chVol[so->ch])>>14;
373}
374
375
376
377int mhL[16];
378int mhR[16];
379int mp=0; //Mix position, for circular array
380// Was stuff for Ghetto Lowpass Filter, now deprecated.
381
382
383inline void synthSample(int * mixL, int * mixR)
384{
385 int a=0;
386 signed long int leftMix=0, rightMix=0, sample=0;
387 for(a=0; a<MAX_VOICES; a++)
388 {
389 if(voices[a].isUsed==1)
390 {
391 sample = synthVoice(a);
392
393 leftMix += (sample*chPanLeft[voices[a].ch])>>7;
394 rightMix += (sample*chPanRight[voices[a].ch])>>7;
395 }
396 }
397
398 //TODO: Automatic Gain Control, anyone?
399 //Or, should this be implemented on the DSP's output volume instead?
400 *mixL = leftMix;
401 *mixR = rightMix;
402
403 return; //No more ghetto lowpass filter.. linear intrpolation works well.
404
405
406 // HACK HACK HACK
407 // This is the infamous Ghetto Lowpass Filter
408 // Now that I have linear interpolation, it should not be needed anymore.
409 /*
410 mp++;
411 if(mp==4)
412 mp=0;
413
414 mhL[mp]=leftMix;
415 mhR[mp]=rightMix;
416
417 *mixL = 0;
418 *mixR = 0;
419
420
421 for(a=0; a<4; a++)
422 {
423 *mixL += mhL[a];
424 *mixR += mhR[a];
425 }
426 *mixL = *mixL>>4;
427 *mixR = *mixR>>4;
428 */
429 // END HACK END HACK END HACK
430}
diff --git a/apps/plugins/midi2wav.c b/apps/plugins/midi2wav.c
new file mode 100644
index 0000000000..f8368535d1
--- /dev/null
+++ b/apps/plugins/midi2wav.c
@@ -0,0 +1,168 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2005 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#define SAMPLE_RATE 48000
20#define MAX_VOICES 100
21
22/* This is for writing to the DSP directly from the Simulator
23#include <stdio.h>
24#include <stdlib.h>
25#include <linux/soundcard.h>
26#include <sys/ioctl.h>
27*/
28
29#include "../../plugin.h"
30#include "midi/midiutil.c"
31#include "midi/guspat.h"
32#include "midi/guspat.c"
33#include "midi/sequencer.c"
34#include "midi/midifile.c"
35#include "midi/synth.c"
36
37
38
39//#include "lib/xxx2wav.h"
40
41int fd=-1; //File descriptor, for opening /dev/dsp and writing to it
42
43extern long tempo; //The sequencer keeps track of this
44
45
46struct plugin_api * rb;
47
48
49
50enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
51{
52 TEST_PLUGIN_API(api);
53 (void)parameter;
54 rb = api;
55 rb->splash(HZ*2, true, "MIDI");
56 midimain();
57 rb->splash(HZ*2, true, "FINISHED PLAYING");
58 return PLUGIN_OK;
59}
60
61
62int midimain()
63{
64 rb->splash(HZ*2, true, "OPENED DSP");
65 fd=rb->open("/dsp.raw", O_WRONLY|O_CREAT);
66/*
67 int arg, status;
68 int bit, samp, ch;
69
70 arg = 16; // sample size
71 status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
72 status = ioctl(fd, SOUND_PCM_READ_BITS, &arg);
73 bit=arg;
74
75
76 arg = 2; //Number of channels, 1=mono
77 status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg);
78 status = ioctl(fd, SOUND_PCM_READ_CHANNELS, &arg);
79 ch=arg;
80
81 arg = SAMPLE_RATE; //Yeah. sampling rate
82 status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);
83 status = ioctl(fd, SOUND_PCM_READ_RATE, &arg);
84 samp=arg;
85*/
86
87 printf("\nHello.\n");
88// initSound(); //Open the computer's sound card
89 int a=0;
90
91 rb->splash(HZ*2, true, "LOADING MIDI");
92
93 struct MIDIfile * mf = loadFile("/test.mid");
94
95 rb->splash(HZ*2, true, "LOADED MIDI");
96 long bpm, nsmp, l;
97
98 int bp=0;
99
100 rb->splash(HZ*2, true, "LOADING PATCHES");
101 initSynth(mf, "/iriver2.cfg", "/drums.cfg"); //Initialize the MIDI syntehsizer
102 rb->splash(HZ*2, true, "START PLAYING");
103
104 signed char buf[3000];
105
106 // tick() will do one MIDI clock tick. Then, there's a loop here that
107 // will generate the right number of samples per MIDI tick. The whole
108 // MIDI playback is timed in terms of this value.. there are no forced
109 // delays or anything. It just produces enough samples for each tick, and
110 // the playback of these samples is what makes the timings right.
111 //
112 // This seems to work quite well.
113
114
115 printf("\nOkay, starting sequencing");
116
117 //Tick() will return 0 if there are no more events left to play
118 while(tick(mf))
119 {
120
121 //Some annoying math to compute the number of samples
122 //to syntehsize per each MIDI tick.
123 bpm=mf->div*1000000/tempo;
124 nsmp=SAMPLE_RATE/bpm;
125
126 //Yes we need to do this math each time because the tempo
127 //could have changed.
128
129 // On second thought, this can be moved to the event that
130 //recalculates the tempo, to save a little bit of CPU time.
131 for(l=0; l<nsmp; l++)
132 {
133 int s1, s2;
134
135 synthSample(&s1, &s2);
136
137
138 //16-bit audio because, well, it's better
139 // But really because ALSA's OSS emulation sounds extremely
140 //noisy and distorted when in 8-bit mode. I still do not know
141 //why this happens.
142 buf[bp]=s1&0XFF; // Low byte first
143 bp++;
144 buf[bp]=s1>>8; //High byte second
145 bp++;
146
147 buf[bp]=s2&0XFF; // Low byte first
148 bp++;
149 buf[bp]=s2>>8; //High byte second
150 bp++;
151
152
153 //As soon as we produce 2000 bytes of sound,
154 //write it to the sound card. Why 2000? I have
155 //no idea. It's 1 AM and I am dead tired.
156 if(bp>=2000)
157 {
158 rb->write(fd, buf, 2000);
159 bp=0;
160 }
161 }
162 }
163
164// unloadFile(mf);
165 printf("\n");
166 rb->close(fd);
167 return 0;
168}