blob: 568c7bb1ce99e2cba9b8dbe272480513fdc4d267 [file] [log] [blame]
Stepan Moskovchenko215e4922005-04-15 06:08:55 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
Nils Wallménius0e496052007-09-24 15:57:32 +00008 * $Id$
Stepan Moskovchenko215e4922005-04-15 06:08:55 +00009 *
10 * Copyright (C) 2005 Stepan Moskovchenko
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
Nils Wallménius0e496052007-09-24 15:57:32 +000019#include "plugin.h"
20#include "guspat.h"
21#include "midiutil.h"
22#include "synth.h"
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000023
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000024extern struct plugin_api * rb;
25
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000026void readTextBlock(int file, char * buf)
27{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000028 char c = 0;
29 do
30 {
31 c = readChar(file);
32 } while(c == '\n' || c == ' ' || c=='\t');
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000033
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000034 rb->lseek(file, -1, SEEK_CUR);
35 int cp = 0;
36 do
37 {
38 c = readChar(file);
39 buf[cp] = c;
40 cp++;
41 } while (c != '\n' && c != ' ' && c != '\t' && !eof(file));
42 buf[cp-1]=0;
43 rb->lseek(file, -1, SEEK_CUR);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000044}
45
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000046/* Filename is the name of the config file */
47/* The MIDI file should have been loaded at this point */
Stepan Moskovchenko58112142005-04-15 20:27:04 +000048int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig)
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000049{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000050 char patchUsed[128];
51 char drumUsed[128];
52 int a=0;
53 for(a=0; a<MAX_VOICES; a++)
54 {
55 voices[a].cp=0;
56 voices[a].vol=0;
57 voices[a].ch=0;
58 voices[a].isUsed=0;
59 voices[a].note=0;
60 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000061
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000062 for(a=0; a<16; a++)
63 {
64 chVol[a]=100; /* Default, not quite full blast.. */
Nils Wallméniuse1940b82007-10-04 19:36:42 +000065 chPan[a]=64; /* Center */
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000066 chPat[a]=0; /* Ac Gr Piano */
Nils Wallméniuse1940b82007-10-04 19:36:42 +000067 chPW[a]=256; /* .. not .. bent ? */
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000068 }
69 for(a=0; a<128; a++)
70 {
71 patchSet[a]=NULL;
72 drumSet[a]=NULL;
73 patchUsed[a]=0;
74 drumUsed[a]=0;
75 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000076
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000077 /*
78 * Always load the piano.
79 * Some files will assume its loaded without specifically
80 * issuing a Patch command... then we wonder why we can't hear anything
81 */
82 patchUsed[0]=1;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000083
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000084 /* Scan the file to see what needs to be loaded */
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +000085 if(mf != NULL)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000086 {
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +000087 for(a=0; a<mf->numTracks; a++)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000088 {
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +000089 unsigned int ts=0;
90
91 if(mf->tracks[a] == NULL)
92 {
93 printf("NULL TRACK !!!");
94 rb->splash(HZ*2, "Null Track in loader.");
95 return -1;
96 }
97
98 for(ts=0; ts<mf->tracks[a]->numEvents; ts++)
99 {
100
101 if((getEvent(mf->tracks[a], ts)->status) == (MIDI_NOTE_ON+9))
102 drumUsed[getEvent(mf->tracks[a], ts)->d1]=1;
103
104 if( (getEvent(mf->tracks[a], ts)->status & 0xF0) == MIDI_PRGM)
105 patchUsed[getEvent(mf->tracks[a], ts)->d1]=1;
106 }
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000107 }
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +0000108 } else
109 {
110 /* Initialize the whole drum set */
111 for(a=0; a<128; a++)
112 drumUsed[a]=1;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000113
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000114 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000115
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000116 int file = rb->open(filename, O_RDONLY);
Stepan Moskovchenko68af7ba2006-05-07 07:12:07 +0000117 if(file < 0)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000118 {
Jens Arnoldb1f00492007-04-21 05:35:17 +0000119 printf("");
120 printf("No MIDI patchset found.");
121 printf("Please install the instruments.");
122 printf("See Rockbox page for more info.");
Stepan Moskovchenko68af7ba2006-05-07 07:12:07 +0000123
Jens Arnold4d6374c2007-03-16 21:56:08 +0000124 rb->splash(HZ*2, "No Instruments");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000125 return -1;
126 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000127
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000128 char name[40];
129 char fn[40];
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000130
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000131 /* Scan our config file and load the right patches as needed */
132 int c = 0;
Jens Arnold79c8a8c2007-03-17 09:02:53 +0000133 name[0] = '\0';
Jens Arnoldb1f00492007-04-21 05:35:17 +0000134 printf("Loading instruments");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000135 for(a=0; a<128; a++)
136 {
137 while(readChar(file)!=' ' && !eof(file));
138 readTextBlock(file, name);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000139
Nils Wallménius04b34352007-09-10 09:46:36 +0000140 rb->snprintf(fn, 40, ROCKBOX_DIR "/patchset/%s.pat", name);
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000141/* printf("\nLOADING: <%s> ", fn); */
Stepan Moskovchenko58112142005-04-15 20:27:04 +0000142
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000143 if(patchUsed[a]==1)
144 {
145 patchSet[a]=gusload(fn);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000146
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000147 if(patchSet[a] == NULL) /* There was an error loading it */
148 return -1;
149 }
Stepan Moskovchenko58112142005-04-15 20:27:04 +0000150
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000151 while((c != '\n'))
152 c = readChar(file);
153 }
154 rb->close(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000155
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000156 file = rb->open(drumConfig, O_RDONLY);
Stepan Moskovchenko68af7ba2006-05-07 07:12:07 +0000157 if(file < 0)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000158 {
Jens Arnold4d6374c2007-03-16 21:56:08 +0000159 rb->splash(HZ*2, "Bad drum config. Did you install the patchset?");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000160 return -1;
161 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000162
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000163 /* Scan our config file and load the drum data */
164 int idx=0;
165 char number[30];
Jens Arnoldb1f00492007-04-21 05:35:17 +0000166 printf("Loading drums");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000167 while(!eof(file))
168 {
169 readTextBlock(file, number);
170 readTextBlock(file, name);
Nils Wallménius04b34352007-09-10 09:46:36 +0000171 rb->snprintf(fn, 40, ROCKBOX_DIR "/patchset/%s.pat", name);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000172
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000173 idx = rb->atoi(number);
174 if(idx == 0)
175 break;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000176
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000177 if(drumUsed[idx]==1)
178 {
179 drumSet[idx]=gusload(fn);
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000180 if(drumSet[idx] == NULL) /* Error loading patch */
181 return -1;
182 }
Stepan Moskovchenko58112142005-04-15 20:27:04 +0000183
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000184 while((c != '\n') && (c != 255) && (!eof(file)))
185 c = readChar(file);
186 }
187 rb->close(file);
188 return 0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000189}
190
Linus Nielsen Feltzing7c4b7862007-04-11 10:48:50 +0000191#define getSample(s,wf) ((short *)(wf)->data)[s]
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000192
Nils Wallménius6386dbe2007-09-30 11:21:25 +0000193void setPoint(struct SynthObject * so, int pt) ICODE_ATTR;
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000194void setPoint(struct SynthObject * so, int pt)
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000195{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000196 if(so->ch==9) /* Drums, no ADSR */
197 {
198 so->curOffset = 1<<27;
199 so->curRate = 1;
200 return;
201 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000202
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000203 if(so->wf==NULL)
204 {
Jens Arnoldb1f00492007-04-21 05:35:17 +0000205 printf("Crap... null waveform...");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000206 exit(1);
207 }
208 if(so->wf->envRate==NULL)
209 {
Jens Arnoldb1f00492007-04-21 05:35:17 +0000210 printf("Waveform has no envelope set");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000211 exit(1);
212 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000213
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000214 so->curPoint = pt;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000215
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000216 int r;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000217 int rate = so->wf->envRate[pt];
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000218
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000219 r=3-((rate>>6) & 0x3); /* Some blatant Timidity code for rate conversion... */
220 r*=3;
221 r = (rate & 0x3f) << r;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000222
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000223 /*
224 * Okay. This is the rate shift. Timidity defaults to 9, and sets
225 * it to 10 if you use the fast decay option. Slow decay sounds better
226 * on some files, except on some other files... you get chords that aren't
227 * done decaying yet.. and they dont harmonize with the next chord and it
228 * sounds like utter crap. Yes, even Timitidy does that. So I'm going to
229 * default this to 10, and maybe later have an option to set it to 9
230 * for longer decays.
231 */
Stepan Moskovchenko414724e2007-09-30 09:01:38 +0000232 so->curRate = r<<10;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000233
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000234 /*
235 * Do this here because the patches assume a 44100 sampling rate
236 * We've halved our sampling rate, ergo the ADSR code will be
237 * called half the time. Ergo, double the rate to keep stuff
238 * sounding right.
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000239 *
240 * Or just move the 1 up one line to optimize a tiny bit.
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000241 */
Stepan Moskovchenko94d9d152006-10-03 23:27:44 +0000242 /* so->curRate = so->curRate << 1; */
Stepan Moskovchenko1f5fb992005-04-19 15:57:07 +0000243
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000244
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000245 so->targetOffset = so->wf->envOffset[pt]<<(20);
246 if(pt==0)
247 so->curOffset = 0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000248}
249
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000250inline void stopVoice(struct SynthObject * so)
251{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000252 if(so->state == STATE_RAMPDOWN)
253 return;
254 so->state = STATE_RAMPDOWN;
Stepan Moskovchenko80b48822006-10-02 04:13:33 +0000255 so->decay = 0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000256}
257
Nils Wallméniusf619f812007-10-08 19:28:41 +0000258static inline int synthVoice(struct SynthObject * so)
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000259{
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000260 struct GWaveform * wf;
261 register int s;
262 register unsigned int cpShifted;
263 register short s1;
264 register short s2;
265
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000266 wf = so->wf;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000267
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000268
Stepan Moskovchenko80b48822006-10-02 04:13:33 +0000269 /* Is voice being ramped? */
270 if(so->state == STATE_RAMPDOWN)
271 {
272 if(so->decay != 0) /* Ramp has been started */
273 {
274 so->decay = so->decay / 2;
275
276 if(so->decay < 10 && so->decay > -10)
277 so->isUsed = 0;
278
Stepan Moskovchenkoc84461f2006-10-03 21:09:47 +0000279 return so->decay;
Stepan Moskovchenko80b48822006-10-02 04:13:33 +0000280 }
281 } else /* OK to advance voice */
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000282 {
283 so->cp += so->delta;
284 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000285
Stepan Moskovchenko80b48822006-10-02 04:13:33 +0000286
Stepan Moskovchenko94d9d152006-10-03 23:27:44 +0000287 cpShifted = so->cp >> FRACTSIZE;
Stepan Moskovchenko1f5fb992005-04-19 15:57:07 +0000288
Stepan Moskovchenkoc84461f2006-10-03 21:09:47 +0000289
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000290
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000291 s2 = getSample((cpShifted)+1, wf);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000292
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000293 /* LOOP_REVERSE|LOOP_PINGPONG = 24 */
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +0000294 if((wf->mode & (24)) && so->loopState == STATE_LOOPING && (cpShifted < (wf->startLoop)))
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000295 {
296 if(wf->mode & LOOP_REVERSE)
297 {
Stepan Moskovchenkod1e30602007-09-29 02:20:49 +0000298 cpShifted = wf->endLoop-(wf->startLoop-cpShifted);
299 so->cp = (cpShifted)<<FRACTSIZE;
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000300 s2=getSample((cpShifted), wf);
301 }
302 else
Stepan Moskovchenkoc84461f2006-10-03 21:09:47 +0000303 {
Stepan Moskovchenkod1e30602007-09-29 02:20:49 +0000304 so->delta = -so->delta; /* At this point cpShifted is wrong. We need to take a step */
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000305 so->loopDir = LOOPDIR_FORWARD;
306 }
307 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000308
Stepan Moskovchenkoaaf3e322007-09-29 03:07:31 +0000309 if((wf->mode & 28) && (cpShifted >= wf->endLoop))
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000310 {
311 so->loopState = STATE_LOOPING;
312 if((wf->mode & (24)) == 0)
313 {
Stepan Moskovchenkod1e30602007-09-29 02:20:49 +0000314 cpShifted = wf->startLoop + (cpShifted-wf->endLoop);
315 so->cp = (cpShifted)<<FRACTSIZE;
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000316 s2=getSample((cpShifted), wf);
317 }
318 else
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000319 {
320 so->delta = -so->delta;
321 so->loopDir = LOOPDIR_REVERSE;
322 }
323 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000324
Stepan Moskovchenkoc84461f2006-10-03 21:09:47 +0000325 /* Have we overrun? */
326 if( (cpShifted >= (wf->numSamples-1)))
327 {
328 so->cp -= so->delta;
Stepan Moskovchenkoc84461f2006-10-03 21:09:47 +0000329 cpShifted = so->cp >> FRACTSIZE;
330 s2 = getSample((cpShifted)+1, wf);
Stepan Moskovchenkoc84461f2006-10-03 21:09:47 +0000331 stopVoice(so);
332 }
333
334
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000335 /* Better, working, linear interpolation */
Stepan Moskovchenko80b48822006-10-02 04:13:33 +0000336 s1=getSample((cpShifted), wf);
337
Stepan Moskovchenko94d9d152006-10-03 23:27:44 +0000338 s = s1 + ((signed)((s2 - s1) * (so->cp & ((1<<FRACTSIZE)-1)))>>FRACTSIZE);
Stepan Moskovchenko1f5fb992005-04-19 15:57:07 +0000339
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000340
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000341 if(so->curRate == 0)
Stepan Moskovchenkoc84461f2006-10-03 21:09:47 +0000342 {
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000343 stopVoice(so);
Stepan Moskovchenko94d9d152006-10-03 23:27:44 +0000344// so->isUsed = 0;
345
Stepan Moskovchenkoc84461f2006-10-03 21:09:47 +0000346 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000347
Stepan Moskovchenko80b48822006-10-02 04:13:33 +0000348 if(so->ch != 9 && so->state != STATE_RAMPDOWN) /* Stupid ADSR code... and don't do ADSR for drums */
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000349 {
350 if(so->curOffset < so->targetOffset)
351 {
352 so->curOffset += (so->curRate);
353 if(so -> curOffset > so->targetOffset && so->curPoint != 2)
354 {
355 if(so->curPoint != 5)
Stepan Moskovchenko94d9d152006-10-03 23:27:44 +0000356 {
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000357 setPoint(so, so->curPoint+1);
Stepan Moskovchenko94d9d152006-10-03 23:27:44 +0000358 }
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000359 else
Stepan Moskovchenkoc84461f2006-10-03 21:09:47 +0000360 {
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000361 stopVoice(so);
Stepan Moskovchenkoc84461f2006-10-03 21:09:47 +0000362 }
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000363 }
364 } else
365 {
366 so->curOffset -= (so->curRate);
367 if(so -> curOffset < so->targetOffset && so->curPoint != 2)
368 {
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000369
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000370 if(so->curPoint != 5)
Stepan Moskovchenko94d9d152006-10-03 23:27:44 +0000371 {
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000372 setPoint(so, so->curPoint+1);
Stepan Moskovchenko94d9d152006-10-03 23:27:44 +0000373 }
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000374 else
Stepan Moskovchenkoc84461f2006-10-03 21:09:47 +0000375 {
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000376 stopVoice(so);
Stepan Moskovchenkoc84461f2006-10-03 21:09:47 +0000377 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000378
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000379 }
380 }
381 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000382
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000383 if(so->curOffset < 0)
Stepan Moskovchenkoc84461f2006-10-03 21:09:47 +0000384 {
Stepan Moskovchenko94d9d152006-10-03 23:27:44 +0000385 so->curOffset = so->targetOffset;
386 stopVoice(so);
Stepan Moskovchenkoc84461f2006-10-03 21:09:47 +0000387 }
Stepan Moskovchenko94d9d152006-10-03 23:27:44 +0000388
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000389 s = (s * (so->curOffset >> 22) >> 8);
Stepan Moskovchenko1f5fb992005-04-19 15:57:07 +0000390
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000391
Stepan Moskovchenko80b48822006-10-02 04:13:33 +0000392 /* need to set ramp beginning */
393 if(so->state == STATE_RAMPDOWN && so->decay == 0)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000394 {
Stepan Moskovchenkoc84461f2006-10-03 21:09:47 +0000395 so->decay = s*so->volscale>>14;
396 if(so->decay == 0)
397 so->decay = 1; /* stupid junk.. */
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000398 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000399
Stepan Moskovchenko80b48822006-10-02 04:13:33 +0000400
Stepan Moskovchenko28b5afd2006-05-03 19:32:22 +0000401 /* Scaling by channel volume and note volume is done in sequencer.c */
402 /* That saves us some multiplication and pointer operations */
403 return s*so->volscale>>14;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000404}
405
Nils Wallméniusf619f812007-10-08 19:28:41 +0000406/* synth num_samples samples and write them to the */
407/* buffer pointed to by buf_ptr */
408void synthSamples(int32_t *buf_ptr, unsigned int num_samples) ICODE_ATTR;
409void synthSamples(int32_t *buf_ptr, unsigned int num_samples)
410{
411 int i;
412 register int dL;
413 register int dR;
414 register int sample;
415 register struct SynthObject *voicept;
416 while(num_samples>0)
417 {
418 dL=0;
419 dR=0;
420 voicept=&voices[0];
421
422 for(i=MAX_VOICES; i > 0; i--)
423 {
424 if(voicept->isUsed==1)
425 {
426 sample = synthVoice(voicept);
427 dL += sample;
428 sample *= chPan[voicept->ch];
429 dR += sample;
430 }
431 voicept++;
432 }
433
434 dL = (dL << 7) - dR;
435
436 /* combine the left and right 16 bit samples into 32 bits and write */
437 /* to the buffer, left sample in the high word and right in the low word */
438 *buf_ptr=(((dL&0x7FFF80) << 9) | ((dR&0x7FFF80) >> 7));
439
440 buf_ptr++;
441 num_samples--;
442 }
443 /* TODO: Automatic Gain Control, anyone? */
444 /* Or, should this be implemented on the DSP's output volume instead? */
445
446 return; /* No more ghetto lowpass filter. Linear interpolation works well. */
447}
448