diff options
Diffstat (limited to 'apps/plugins/midi')
-rw-r--r-- | apps/plugins/midi/guspat.c | 151 | ||||
-rw-r--r-- | apps/plugins/midi/guspat.h | 94 | ||||
-rw-r--r-- | apps/plugins/midi/midifile.c | 305 | ||||
-rw-r--r-- | apps/plugins/midi/midiutil.c | 262 | ||||
-rw-r--r-- | apps/plugins/midi/sequencer.c | 298 | ||||
-rw-r--r-- | apps/plugins/midi/synth.c | 430 |
6 files changed, 1540 insertions, 0 deletions
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 | |||
20 | extern struct plugin_api * rb; | ||
21 | |||
22 | unsigned int readWord(int file) | ||
23 | { | ||
24 | return (readChar(file)<<0) | (readChar(file)<<8); // | (readChar(file)<<8) | (readChar(file)<<0); | ||
25 | } | ||
26 | |||
27 | unsigned int readDWord(int file) | ||
28 | { | ||
29 | return (readChar(file)<<0) | (readChar(file)<<8) | (readChar(file)<<16) | (readChar(file)<<24); | ||
30 | } | ||
31 | |||
32 | struct 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 | |||
74 | int 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 | |||
90 | struct 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 | ||
20 | const 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 | |||
34 | struct 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 | |||
66 | struct 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 | |||
21 | extern struct plugin_api * rb; | ||
22 | |||
23 | struct Track * readTrack(int file); | ||
24 | int readID(int file); | ||
25 | void bail(const char *); | ||
26 | |||
27 | struct 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 | |||
108 | int rStatus = 0; | ||
109 | |||
110 | //Returns 0 if done, 1 if keep going | ||
111 | int 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 | |||
179 | struct 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 | |||
220 | int 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 | |||
241 | int 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 | |||
250 | int 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 | ||
257 | int 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 | ||
274 | void 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 | |||
300 | void 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 | |||
61 | extern struct plugin_api * rb; | ||
62 | |||
63 | |||
64 | unsigned char chVol[16]; //Channel volume | ||
65 | unsigned char chPanLeft[16]; //Channel panning | ||
66 | unsigned char chPanRight[16]; | ||
67 | unsigned char chPat[16]; //Channel patch | ||
68 | unsigned char chPW[16]; //Channel pitch wheel, MSB | ||
69 | |||
70 | struct GPatch * gusload(char *); | ||
71 | struct GPatch * patchSet[128]; | ||
72 | struct GPatch * drumSet[128]; | ||
73 | struct SynthObject voices[MAX_VOICES]; | ||
74 | |||
75 | |||
76 | |||
77 | struct 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 | |||
91 | struct Event | ||
92 | { | ||
93 | unsigned int delta; | ||
94 | unsigned char status, d1, d2; | ||
95 | unsigned int len; | ||
96 | unsigned char * evData; | ||
97 | }; | ||
98 | |||
99 | struct 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 | |||
109 | struct 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 | |||
121 | void *my_malloc(int size); | ||
122 | |||
123 | void *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 | |||
147 | void *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 | |||
180 | void * allocate(int size) | ||
181 | { | ||
182 | return alloc(size); | ||
183 | } | ||
184 | |||
185 | void sendEvent(struct Event * ev); | ||
186 | int tick(struct MIDIfile * mf); | ||
187 | inline void setPoint(struct SynthObject * so, int pt); | ||
188 | struct Event * getEvent(struct Track * tr, int evNum); | ||
189 | |||
190 | unsigned char readChar(int file) | ||
191 | { | ||
192 | char buf[2]; | ||
193 | rb->read(file, &buf, 1); | ||
194 | return buf[0]; | ||
195 | } | ||
196 | |||
197 | unsigned char * readData(int file, int len) | ||
198 | { | ||
199 | unsigned char * dat = allocate(len); | ||
200 | rb->read(file, dat, len); | ||
201 | return dat; | ||
202 | } | ||
203 | |||
204 | int 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 | |||
214 | void printf(char *fmt, ...) {} | ||
215 | |||
216 | //#define my_malloc(a) malloc(a) | ||
217 | |||
218 | |||
219 | void *audio_bufferbase; | ||
220 | void *audio_bufferpointer; | ||
221 | unsigned int audio_buffer_free; | ||
222 | |||
223 | |||
224 | |||
225 | |||
226 | void *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 | |||
250 | void setmallocpos(void *pointer) | ||
251 | { | ||
252 | audio_bufferpointer = pointer; | ||
253 | audio_buffer_free = audio_bufferpointer - audio_bufferbase; | ||
254 | } | ||
255 | |||
256 | void exit(int code) | ||
257 | { | ||
258 | } | ||
259 | |||
260 | void 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 | |||
20 | extern struct plugin_api * rb; | ||
21 | |||
22 | long tempo=375000; | ||
23 | |||
24 | |||
25 | void setVol(int ch, int vol) | ||
26 | { | ||
27 | printf("\nvolume[%d] %d ==> %d", ch, chVol[ch], vol); | ||
28 | chVol[ch]=vol; | ||
29 | } | ||
30 | |||
31 | void 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 | |||
40 | void 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 | */ | ||
52 | long 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 | |||
65 | void 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 | |||
74 | void 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 | |||
89 | void 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 | |||
164 | void 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 | |||
188 | void 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 | |||
242 | int 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 | |||
21 | extern struct plugin_api * rb; | ||
22 | |||
23 | struct Event * getEvent(struct Track * tr, int evNum) | ||
24 | { | ||
25 | return tr->dataBlock + (evNum*sizeof(struct Event)); | ||
26 | } | ||
27 | |||
28 | void 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 | ||
52 | void 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 | |||
165 | inline 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 | |||
201 | inline 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 | |||
252 | long msi=0; | ||
253 | |||
254 | inline 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 | |||
263 | int rampDown = 0; | ||
264 | |||
265 | inline 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 | |||
377 | int mhL[16]; | ||
378 | int mhR[16]; | ||
379 | int mp=0; //Mix position, for circular array | ||
380 | // Was stuff for Ghetto Lowpass Filter, now deprecated. | ||
381 | |||
382 | |||
383 | inline 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 | } | ||