diff options
Diffstat (limited to 'apps/plugins/midi/synth.c')
-rw-r--r-- | apps/plugins/midi/synth.c | 650 |
1 files changed, 319 insertions, 331 deletions
diff --git a/apps/plugins/midi/synth.c b/apps/plugins/midi/synth.c index bafaf1c7ca..50becf32a4 100644 --- a/apps/plugins/midi/synth.c +++ b/apps/plugins/midi/synth.c | |||
@@ -20,158 +20,164 @@ extern struct plugin_api * rb; | |||
20 | 20 | ||
21 | struct Event * getEvent(struct Track * tr, int evNum) | 21 | struct Event * getEvent(struct Track * tr, int evNum) |
22 | { | 22 | { |
23 | return tr->dataBlock + (evNum*sizeof(struct Event)); | 23 | return tr->dataBlock + (evNum*sizeof(struct Event)); |
24 | } | 24 | } |
25 | 25 | ||
26 | void readTextBlock(int file, char * buf) | 26 | void readTextBlock(int file, char * buf) |
27 | { | 27 | { |
28 | char c = 0; | 28 | char c = 0; |
29 | do | 29 | do |
30 | { | 30 | { |
31 | c = readChar(file); | 31 | c = readChar(file); |
32 | } while(c == '\n' || c == ' ' || c=='\t'); | 32 | } while(c == '\n' || c == ' ' || c=='\t'); |
33 | 33 | ||
34 | rb->lseek(file, -1, SEEK_CUR); | 34 | rb->lseek(file, -1, SEEK_CUR); |
35 | int cp = 0; | 35 | int cp = 0; |
36 | do | 36 | do |
37 | { | 37 | { |
38 | c = readChar(file); | 38 | c = readChar(file); |
39 | buf[cp] = c; | 39 | buf[cp] = c; |
40 | cp++; | 40 | cp++; |
41 | } while (c != '\n' && c != ' ' && c != '\t' && !eof(file)); | 41 | } while (c != '\n' && c != ' ' && c != '\t' && !eof(file)); |
42 | buf[cp-1]=0; | 42 | buf[cp-1]=0; |
43 | rb->lseek(file, -1, SEEK_CUR); | 43 | rb->lseek(file, -1, SEEK_CUR); |
44 | } | 44 | } |
45 | 45 | ||
46 | 46 | ||
47 | 47 | ||
48 | //Filename is the name of the config file | 48 | /* Filename is the name of the config file */ |
49 | //The MIDI file should have been loaded at this point | 49 | /* The MIDI file should have been loaded at this point */ |
50 | int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig) | 50 | int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig) |
51 | { | 51 | { |
52 | char patchUsed[128]; | 52 | char patchUsed[128]; |
53 | char drumUsed[128]; | 53 | char drumUsed[128]; |
54 | int a=0; | 54 | int a=0; |
55 | for(a=0; a<MAX_VOICES; a++) | 55 | for(a=0; a<MAX_VOICES; a++) |
56 | { | 56 | { |
57 | voices[a].cp=0; | 57 | voices[a].cp=0; |
58 | voices[a].vol=0; | 58 | voices[a].vol=0; |
59 | voices[a].ch=0; | 59 | voices[a].ch=0; |
60 | voices[a].isUsed=0; | 60 | voices[a].isUsed=0; |
61 | voices[a].note=0; | 61 | voices[a].note=0; |
62 | } | 62 | } |
63 | 63 | ||
64 | for(a=0; a<16; a++) | 64 | for(a=0; a<16; a++) |
65 | { | 65 | { |
66 | chVol[a]=100; //Default, not quite full blast.. | 66 | chVol[a]=100; /* Default, not quite full blast.. */ |
67 | chPanLeft[a]=64; //Center | 67 | chPanLeft[a]=64; /* Center */ |
68 | chPanRight[a]=64; //Center | 68 | chPanRight[a]=64; /* Center */ |
69 | chPat[a]=0; //Ac Gr Piano | 69 | chPat[a]=0; /* Ac Gr Piano */ |
70 | chPW[a]=64; // .. not .. bent ? | 70 | chPW[a]=64; /* .. not .. bent ? */ |
71 | } | 71 | } |
72 | for(a=0; a<128; a++) | 72 | for(a=0; a<128; a++) |
73 | { | 73 | { |
74 | patchSet[a]=NULL; | 74 | patchSet[a]=NULL; |
75 | drumSet[a]=NULL; | 75 | drumSet[a]=NULL; |
76 | patchUsed[a]=0; | 76 | patchUsed[a]=0; |
77 | drumUsed[a]=0; | 77 | drumUsed[a]=0; |
78 | } | 78 | } |
79 | 79 | ||
80 | //Always load the piano. | 80 | /* |
81 | //Some files will assume its loaded without specifically | 81 | * Always load the piano. |
82 | //issuing a Patch command... then we wonder why we can't hear anything | 82 | * Some files will assume its loaded without specifically |
83 | patchUsed[0]=1; | 83 | * issuing a Patch command... then we wonder why we can't hear anything |
84 | 84 | */ | |
85 | //Scan the file to see what needs to be loaded | 85 | patchUsed[0]=1; |
86 | for(a=0; a<mf->numTracks; a++) | 86 | |
87 | { | 87 | /* Scan the file to see what needs to be loaded */ |
88 | int ts=0; | 88 | for(a=0; a<mf->numTracks; a++) |
89 | 89 | { | |
90 | if(mf->tracks[a] == NULL) | 90 | unsigned int ts=0; |
91 | { | 91 | |
92 | printf("\nNULL TRACK !!!"); | 92 | if(mf->tracks[a] == NULL) |
93 | rb->splash(HZ*2, true, "Null Track in loader."); | 93 | { |
94 | return -1; | 94 | printf("\nNULL TRACK !!!"); |
95 | } | 95 | rb->splash(HZ*2, true, "Null Track in loader."); |
96 | 96 | return -1; | |
97 | for(ts=0; ts<mf->tracks[a]->numEvents; ts++) | 97 | } |
98 | { | 98 | |
99 | 99 | for(ts=0; ts<mf->tracks[a]->numEvents; ts++) | |
100 | if((getEvent(mf->tracks[a], ts)->status) == (MIDI_NOTE_ON+9)) | 100 | { |
101 | drumUsed[getEvent(mf->tracks[a], ts)->d1]=1; | 101 | |
102 | 102 | if((getEvent(mf->tracks[a], ts)->status) == (MIDI_NOTE_ON+9)) | |
103 | if( (getEvent(mf->tracks[a], ts)->status & 0xF0) == MIDI_PRGM) | 103 | drumUsed[getEvent(mf->tracks[a], ts)->d1]=1; |
104 | { | 104 | |
105 | if(patchUsed[getEvent(mf->tracks[a], ts)->d1]==0) | 105 | if( (getEvent(mf->tracks[a], ts)->status & 0xF0) == MIDI_PRGM) |
106 | printf("\nI need to load patch %d.", getEvent(mf->tracks[a], ts)->d1); | 106 | { |
107 | patchUsed[getEvent(mf->tracks[a], ts)->d1]=1; | 107 | if(patchUsed[getEvent(mf->tracks[a], ts)->d1]==0) |
108 | } | 108 | printf("\nI need to load patch %d.", getEvent(mf->tracks[a], ts)->d1); |
109 | } | 109 | patchUsed[getEvent(mf->tracks[a], ts)->d1]=1; |
110 | } | 110 | } |
111 | 111 | } | |
112 | int file = rb->open(filename, O_RDONLY); | 112 | } |
113 | if(file == -1) | 113 | |
114 | { | 114 | int file = rb->open(filename, O_RDONLY); |
115 | rb->splash(HZ*2, true, "Bad patch config.\nDid you install the patchset?"); | 115 | if(file == -1) |
116 | return -1; | 116 | { |
117 | } | 117 | rb->splash(HZ*2, true, "Bad patch config.\nDid you install the patchset?"); |
118 | 118 | return -1; | |
119 | char name[40]; | 119 | } |
120 | char fn[40]; | 120 | |
121 | 121 | char name[40]; | |
122 | //Scan our config file and load the right patches as needed | 122 | char fn[40]; |
123 | int c = 0; | 123 | |
124 | rb->snprintf(name, 40, ""); | 124 | /* Scan our config file and load the right patches as needed */ |
125 | for(a=0; a<128; a++) | 125 | int c = 0; |
126 | { | 126 | rb->snprintf(name, 40, ""); |
127 | while(readChar(file)!=' ' && !eof(file)); | 127 | for(a=0; a<128; a++) |
128 | readTextBlock(file, name); | 128 | { |
129 | 129 | while(readChar(file)!=' ' && !eof(file)); | |
130 | rb->snprintf(fn, 40, "/.rockbox/patchset/%s.pat", name); | 130 | readTextBlock(file, name); |
131 | printf("\nLOADING: <%s> ", fn); | 131 | |
132 | 132 | rb->snprintf(fn, 40, "/.rockbox/patchset/%s.pat", name); | |
133 | if(patchUsed[a]==1) | 133 | printf("\nLOADING: <%s> ", fn); |
134 | patchSet[a]=gusload(fn); | 134 | |
135 | 135 | if(patchUsed[a]==1) | |
136 | // if(patchSet[a] == NULL) | 136 | { |
137 | // return -1; | 137 | patchSet[a]=gusload(fn); |
138 | 138 | ||
139 | while((c != '\n')) | 139 | if(patchSet[a] == NULL) /* There was an error loading it */ |
140 | c = readChar(file); | 140 | return -1; |
141 | } | 141 | } |
142 | rb->close(file); | 142 | |
143 | 143 | while((c != '\n')) | |
144 | file = rb->open(drumConfig, O_RDONLY); | 144 | c = readChar(file); |
145 | if(file == -1) | 145 | } |
146 | { | 146 | rb->close(file); |
147 | rb->splash(HZ*2, true, "Bad drum config.\nDid you install the patchset?"); | 147 | |
148 | return -1; | 148 | file = rb->open(drumConfig, O_RDONLY); |
149 | } | 149 | if(file == -1) |
150 | 150 | { | |
151 | //Scan our config file and load the drum data | 151 | rb->splash(HZ*2, true, "Bad drum config.\nDid you install the patchset?"); |
152 | int idx=0; | 152 | return -1; |
153 | char number[30]; | 153 | } |
154 | while(!eof(file)) | 154 | |
155 | { | 155 | /* Scan our config file and load the drum data */ |
156 | readTextBlock(file, number); | 156 | int idx=0; |
157 | readTextBlock(file, name); | 157 | char number[30]; |
158 | rb->snprintf(fn, 40, "/.rockbox/patchset/%s.pat", name); | 158 | while(!eof(file)) |
159 | 159 | { | |
160 | idx = rb->atoi(number); | 160 | readTextBlock(file, number); |
161 | if(idx == 0) | 161 | readTextBlock(file, name); |
162 | break; | 162 | rb->snprintf(fn, 40, "/.rockbox/patchset/%s.pat", name); |
163 | 163 | ||
164 | if(drumUsed[idx]==1) | 164 | idx = rb->atoi(number); |
165 | drumSet[idx]=gusload(fn); | 165 | if(idx == 0) |
166 | 166 | break; | |
167 | // if(drumSet[idx] == NULL) | 167 | |
168 | // return -1; | 168 | if(drumUsed[idx]==1) |
169 | 169 | { | |
170 | while((c != '\n') && (c != 255) && (!eof(file))) | 170 | drumSet[idx]=gusload(fn); |
171 | c = readChar(file); | 171 | |
172 | } | 172 | if(drumSet[idx] == NULL) /* Error loading patch */ |
173 | rb->close(file); | 173 | return -1; |
174 | return 0; | 174 | } |
175 | |||
176 | while((c != '\n') && (c != 255) && (!eof(file))) | ||
177 | c = readChar(file); | ||
178 | } | ||
179 | rb->close(file); | ||
180 | return 0; | ||
175 | } | 181 | } |
176 | 182 | ||
177 | 183 | ||
@@ -182,7 +188,7 @@ struct GWaveform * wf IDATA_ATTR; | |||
182 | int s IDATA_ATTR; | 188 | int s IDATA_ATTR; |
183 | short s1 IDATA_ATTR; | 189 | short s1 IDATA_ATTR; |
184 | short s2 IDATA_ATTR; | 190 | short s2 IDATA_ATTR; |
185 | short sample IDATA_ATTR; //For synthSample | 191 | short sample IDATA_ATTR; /* For synthSample */ |
186 | unsigned int cpShifted IDATA_ATTR; | 192 | unsigned int cpShifted IDATA_ATTR; |
187 | 193 | ||
188 | unsigned char b1 IDATA_ATTR; | 194 | unsigned char b1 IDATA_ATTR; |
@@ -191,31 +197,9 @@ unsigned char b2 IDATA_ATTR; | |||
191 | 197 | ||
192 | inline int getSample(int s) | 198 | inline int getSample(int s) |
193 | { | 199 | { |
194 | 200 | /* Sign conversion moved to guspat.c */ | |
195 | //16 bit samples | 201 | /* 8bit conversion NOT YET IMPLEMENTED in guspat.c */ |
196 | if(wf->mode&1) | 202 | return ((short *) wf->data)[s]; |
197 | { | ||
198 | |||
199 | if(s<<1 >= wf->wavSize) | ||
200 | { | ||
201 | printf("\n!!!!! %d \t %d", s<<1, wf->wavSize); | ||
202 | return 0; | ||
203 | } | ||
204 | // signed short a = ((short *)wf->data)[s]; | ||
205 | |||
206 | //Sign conversion moved into guspat.c | ||
207 | b1=wf->data[s<<1]+((wf->mode & 2) << 6); | ||
208 | b2=wf->data[(s<<1)|1]+((wf->mode & 2) << 6); | ||
209 | return (b1 | (b2<<8)) ; | ||
210 | |||
211 | //Get rid of this sometime | ||
212 | } | ||
213 | else | ||
214 | { //8-bit samples | ||
215 | //Do we even have anything 8-bit in our set? | ||
216 | int b1=wf->data[s]+((wf->mode & 2) << 6); | ||
217 | return b1<<8; | ||
218 | } | ||
219 | } | 203 | } |
220 | 204 | ||
221 | 205 | ||
@@ -223,190 +207,194 @@ inline int getSample(int s) | |||
223 | 207 | ||
224 | inline void setPoint(struct SynthObject * so, int pt) | 208 | inline void setPoint(struct SynthObject * so, int pt) |
225 | { | 209 | { |
226 | if(so->ch==9) //Drums, no ADSR | 210 | if(so->ch==9) /* Drums, no ADSR */ |
227 | { | 211 | { |
228 | so->curOffset = 1<<27; | 212 | so->curOffset = 1<<27; |
229 | so->curRate = 1; | 213 | so->curRate = 1; |
230 | return; | 214 | return; |
231 | } | 215 | } |
232 | 216 | ||
233 | if(so->wf==NULL) | 217 | if(so->wf==NULL) |
234 | { | 218 | { |
235 | printf("\nCrap... null waveform..."); | 219 | printf("\nCrap... null waveform..."); |
236 | exit(1); | 220 | exit(1); |
237 | } | 221 | } |
238 | if(so->wf->envRate==NULL) | 222 | if(so->wf->envRate==NULL) |
239 | { | 223 | { |
240 | printf("\nWaveform has no envelope set"); | 224 | printf("\nWaveform has no envelope set"); |
241 | exit(1); | 225 | exit(1); |
242 | } | 226 | } |
243 | 227 | ||
244 | so->curPoint = pt; | 228 | so->curPoint = pt; |
245 | 229 | ||
246 | int r=0; | 230 | int r=0; |
247 | int rate = so->wf->envRate[pt]; | 231 | int rate = so->wf->envRate[pt]; |
248 | 232 | ||
249 | r=3-((rate>>6) & 0x3); // Some blatant Timidity code for rate conversion... | 233 | r=3-((rate>>6) & 0x3); /* Some blatant Timidity code for rate conversion... */ |
250 | r*=3; | 234 | r*=3; |
251 | r = (rate & 0x3f) << r; | 235 | r = (rate & 0x3f) << r; |
252 | 236 | ||
253 | /* | 237 | /* |
254 | Okay. This is the rate shift. Timidity defaults to 9, and sets | 238 | * Okay. This is the rate shift. Timidity defaults to 9, and sets |
255 | it to 10 if you use the fast decay option. Slow decay sounds better | 239 | * it to 10 if you use the fast decay option. Slow decay sounds better |
256 | on some files, except on some other files... you get chords that aren't | 240 | * on some files, except on some other files... you get chords that aren't |
257 | done decaying yet.. and they dont harmonize with the next chord and it | 241 | * done decaying yet.. and they dont harmonize with the next chord and it |
258 | sounds like utter crap. Yes, even Timitidy does that. So I'm going to | 242 | * sounds like utter crap. Yes, even Timitidy does that. So I'm going to |
259 | default this to 10, and maybe later have an option to set it to 9 | 243 | * default this to 10, and maybe later have an option to set it to 9 |
260 | for longer decays. | 244 | * for longer decays. |
261 | */ | 245 | */ |
262 | so->curRate = r<<10; | 246 | so->curRate = r<<10; |
263 | 247 | ||
264 | //Do this here because the patches assume a 44100 sampling rate | 248 | /* |
265 | //We've halved our sampling rate, ergo the ADSR code will be | 249 | * Do this here because the patches assume a 44100 sampling rate |
266 | //called half the time. Ergo, double the rate to keep stuff | 250 | * We've halved our sampling rate, ergo the ADSR code will be |
267 | //sounding right. | 251 | * called half the time. Ergo, double the rate to keep stuff |
268 | so->curRate = so->curRate << 1; | 252 | * sounding right. |
269 | 253 | */ | |
270 | 254 | so->curRate = so->curRate << 1; | |
271 | so->targetOffset = so->wf->envOffset[pt]<<(20); | 255 | |
272 | if(pt==0) | 256 | |
273 | so->curOffset = 0; | 257 | so->targetOffset = so->wf->envOffset[pt]<<(20); |
258 | if(pt==0) | ||
259 | so->curOffset = 0; | ||
274 | } | 260 | } |
275 | 261 | ||
276 | 262 | ||
277 | inline void stopVoice(struct SynthObject * so) | 263 | inline void stopVoice(struct SynthObject * so) |
278 | { | 264 | { |
279 | if(so->state == STATE_RAMPDOWN) | 265 | if(so->state == STATE_RAMPDOWN) |
280 | return; | 266 | return; |
281 | so->state = STATE_RAMPDOWN; | 267 | so->state = STATE_RAMPDOWN; |
282 | so->decay = 255; | 268 | so->decay = 255; |
283 | 269 | ||
284 | } | 270 | } |
285 | 271 | ||
286 | 272 | ||
287 | inline signed short int synthVoice() | 273 | inline signed short int synthVoice() |
288 | { | 274 | { |
289 | so = &voices[currentVoice]; | 275 | so = &voices[currentVoice]; |
290 | wf = so->wf; | 276 | wf = so->wf; |
291 | 277 | ||
292 | 278 | ||
293 | if(so->state != STATE_RAMPDOWN) | 279 | if(so->state != STATE_RAMPDOWN) |
294 | { | 280 | { |
295 | so->cp += so->delta; | 281 | so->cp += so->delta; |
296 | } | 282 | } |
297 | 283 | ||
298 | cpShifted = so->cp >> 10; | 284 | cpShifted = so->cp >> 10; |
299 | 285 | ||
300 | if( (cpShifted >= (wf->wavSize>>1)) && (so->state != STATE_RAMPDOWN)) | 286 | if( (cpShifted > (wf->numSamples) && (so->state != STATE_RAMPDOWN))) |
301 | stopVoice(so); | 287 | { |
288 | stopVoice(so); | ||
289 | } | ||
302 | 290 | ||
303 | s2 = getSample((cpShifted)+1); | 291 | s2 = getSample((cpShifted)+1); |
304 | 292 | ||
305 | if((wf->mode & (LOOP_REVERSE|LOOP_PINGPONG)) && so->loopState == STATE_LOOPING && (cpShifted <= (wf->startLoop>>1))) | 293 | /* LOOP_REVERSE|LOOP_PINGPONG = 24 */ |
306 | { | 294 | if((wf->mode & (24)) && so->loopState == STATE_LOOPING && (cpShifted <= (wf->startLoop))) |
307 | if(wf->mode & LOOP_REVERSE) | 295 | { |
308 | { | 296 | if(wf->mode & LOOP_REVERSE) |
309 | so->cp = (wf->endLoop)<<9; | 297 | { |
310 | cpShifted = so->cp >> 10; | 298 | so->cp = (wf->endLoop)<<10; |
311 | s2=getSample((cpShifted)); | 299 | cpShifted = wf->endLoop; |
312 | } else | 300 | s2=getSample((cpShifted)); |
313 | { | 301 | } else |
314 | so->delta = -so->delta; | 302 | { |
315 | so->loopDir = LOOPDIR_FORWARD; | 303 | so->delta = -so->delta; |
316 | } | 304 | so->loopDir = LOOPDIR_FORWARD; |
317 | } | 305 | } |
318 | 306 | } | |
319 | if((wf->mode & 28) && (so->cp>>10 >= wf->endLoop>>1)) | 307 | |
320 | { | 308 | if((wf->mode & 28) && (cpShifted >= wf->endLoop)) |
321 | so->loopState = STATE_LOOPING; | 309 | { |
322 | if((wf->mode & (24)) == 0) | 310 | so->loopState = STATE_LOOPING; |
323 | { | 311 | if((wf->mode & (24)) == 0) |
324 | so->cp = (wf->startLoop)<<9; | 312 | { |
325 | cpShifted = so->cp >> 10; | 313 | so->cp = (wf->startLoop)<<10; |
326 | s2=getSample((cpShifted)); | 314 | cpShifted = wf->startLoop; |
327 | } else | 315 | s2=getSample((cpShifted)); |
328 | { | 316 | } else |
329 | so->delta = -so->delta; | 317 | { |
330 | so->loopDir = LOOPDIR_REVERSE; | 318 | so->delta = -so->delta; |
331 | } | 319 | so->loopDir = LOOPDIR_REVERSE; |
332 | } | 320 | } |
333 | 321 | } | |
334 | //Better, working, linear interpolation | 322 | |
335 | s1=getSample((cpShifted)); | 323 | /* Better, working, linear interpolation */ |
336 | s = s1 + ((signed)((s2 - s1) * (so->cp & 1023))>>10); | 324 | s1=getSample((cpShifted)); |
337 | 325 | s = s1 + ((signed)((s2 - s1) * (so->cp & 1023))>>10); | |
338 | 326 | ||
339 | //ADSR COMMENT WOULD GO FROM HERE......... | 327 | |
340 | 328 | /* ADSR COMMENT WOULD GO FROM HERE.........*/ | |
341 | if(so->curRate == 0) | 329 | |
342 | stopVoice(so); | 330 | if(so->curRate == 0) |
343 | 331 | stopVoice(so); | |
344 | 332 | ||
345 | if(so->ch != 9) //Stupid ADSR code... and don't do ADSR for drums | 333 | |
346 | { | 334 | if(so->ch != 9) /* Stupid ADSR code... and don't do ADSR for drums */ |
347 | if(so->curOffset < so->targetOffset) | 335 | { |
348 | { | 336 | if(so->curOffset < so->targetOffset) |
349 | so->curOffset += (so->curRate); | 337 | { |
350 | if(so -> curOffset > so->targetOffset && so->curPoint != 2) | 338 | so->curOffset += (so->curRate); |
351 | { | 339 | if(so -> curOffset > so->targetOffset && so->curPoint != 2) |
352 | if(so->curPoint != 5) | 340 | { |
353 | setPoint(so, so->curPoint+1); | 341 | if(so->curPoint != 5) |
354 | else | 342 | setPoint(so, so->curPoint+1); |
355 | stopVoice(so); | 343 | else |
356 | } | 344 | stopVoice(so); |
357 | } else | 345 | } |
358 | { | 346 | } else |
359 | so->curOffset -= (so->curRate); | 347 | { |
360 | if(so -> curOffset < so->targetOffset && so->curPoint != 2) | 348 | so->curOffset -= (so->curRate); |
361 | { | 349 | if(so -> curOffset < so->targetOffset && so->curPoint != 2) |
362 | 350 | { | |
363 | if(so->curPoint != 5) | 351 | |
364 | setPoint(so, so->curPoint+1); | 352 | if(so->curPoint != 5) |
365 | else | 353 | setPoint(so, so->curPoint+1); |
366 | stopVoice(so); | 354 | else |
367 | 355 | stopVoice(so); | |
368 | } | 356 | |
369 | } | 357 | } |
370 | } | 358 | } |
371 | 359 | } | |
372 | if(so->curOffset < 0) | 360 | |
373 | so->isUsed=0; //This is OK | 361 | if(so->curOffset < 0) |
374 | 362 | so->isUsed=0; /* This is OK because offset faded it out already */ | |
375 | 363 | ||
376 | s = (s * (so->curOffset >> 22) >> 6); | 364 | |
377 | 365 | s = (s * (so->curOffset >> 22) >> 8); | |
378 | // ............. TO HERE | 366 | |
379 | 367 | /* ............. TO HERE */ | |
380 | 368 | ||
381 | if(so->state == STATE_RAMPDOWN) | 369 | |
382 | { | 370 | if(so->state == STATE_RAMPDOWN) |
383 | so->decay--; | 371 | { |
384 | if(so->decay == 0) | 372 | so->decay--; |
385 | so->isUsed=0; | 373 | if(so->decay == 0) |
386 | } | 374 | so->isUsed=0; |
387 | 375 | s = (s * so->decay) >> 8; | |
388 | s = s * so->decay; s = s >> 10; | 376 | } |
389 | 377 | ||
390 | return s*((signed short int)so->vol*(signed short int)chVol[so->ch])>>14; | 378 | return s*((signed short int)so->vol*(signed short int)chVol[so->ch])>>14; |
391 | } | 379 | } |
392 | 380 | ||
393 | 381 | ||
394 | inline void synthSample(int * mixL, int * mixR) | 382 | inline void synthSample(int * mixL, int * mixR) |
395 | { | 383 | { |
396 | // signed int leftMix=0, rightMix=0, | 384 | *mixL = 0; |
397 | *mixL = 0; | 385 | *mixR = 0; |
398 | *mixR = 0; | 386 | for(currentVoice=0; currentVoice<MAX_VOICES; currentVoice++) |
399 | for(currentVoice=0; currentVoice<MAX_VOICES; currentVoice++) | 387 | { |
400 | { | 388 | if(voices[currentVoice].isUsed==1) |
401 | if(voices[currentVoice].isUsed==1) | 389 | { |
402 | { | 390 | sample = synthVoice(currentVoice); |
403 | sample = synthVoice(currentVoice); | 391 | *mixL += (sample*chPanLeft[voices[currentVoice].ch])>>7; |
404 | *mixL += (sample*chPanLeft[voices[currentVoice].ch])>>7; | 392 | *mixR += (sample*chPanRight[voices[currentVoice].ch])>>7; |
405 | *mixR += (sample*chPanRight[voices[currentVoice].ch])>>7; | 393 | } |
406 | } | 394 | } |
407 | } | 395 | |
408 | 396 | /* TODO: Automatic Gain Control, anyone? */ | |
409 | //TODO: Automatic Gain Control, anyone? | 397 | /* Or, should this be implemented on the DSP's output volume instead? */ |
410 | //Or, should this be implemented on the DSP's output volume instead? | 398 | |
411 | return; //No more ghetto lowpass filter.. linear intrpolation works well. | 399 | return; /* No more ghetto lowpass filter.. linear intrpolation works well. */ |
412 | } | 400 | } |