blob: 08197220306a3f183744a6a0f54899ba408869e3 [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 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
Nils Wallménius0e496052007-09-24 15:57:32 +000021#include "plugin.h"
22#include "guspat.h"
23#include "midiutil.h"
24#include "synth.h"
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000025
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000026extern struct plugin_api * rb;
27
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000028void readTextBlock(int file, char * buf)
29{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000030 char c = 0;
31 do
32 {
33 c = readChar(file);
34 } while(c == '\n' || c == ' ' || c=='\t');
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000035
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000036 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);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000046}
47
Stepan Moskovchenkocd963d82007-11-03 04:09:38 +000048void resetControllers()
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000049{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000050 int a=0;
51 for(a=0; a<MAX_VOICES; a++)
52 {
53 voices[a].cp=0;
54 voices[a].vol=0;
55 voices[a].ch=0;
Nils Wallménius0fd4c2e2007-11-11 01:02:45 +000056 voices[a].isUsed=false;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000057 voices[a].note=0;
58 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000059
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000060 for(a=0; a<16; a++)
61 {
62 chVol[a]=100; /* Default, not quite full blast.. */
Nils Wallméniuse1940b82007-10-04 19:36:42 +000063 chPan[a]=64; /* Center */
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000064 chPat[a]=0; /* Ac Gr Piano */
Nils Wallméniuse1940b82007-10-04 19:36:42 +000065 chPW[a]=256; /* .. not .. bent ? */
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +000066 chPBDepth[a]=2; /* Default bend value is 2 */
Stepan Moskovchenkod33645b2007-10-17 03:48:24 +000067 chPBNoteOffset[a]=0; /* No offset */
68 chPBFractBend[a]=65536; /* Center.. no bend */
Stepan Moskovchenko47d83232007-10-21 19:47:33 +000069 chLastCtrlMSB[a]=0; /* Set to pitch bend depth */
70 chLastCtrlLSB[a]=0; /* Set to pitch bend depth */
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000071 }
Stepan Moskovchenkocd963d82007-11-03 04:09:38 +000072}
73
74/* Filename is the name of the config file */
75/* The MIDI file should have been loaded at this point */
76int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig)
77{
78 char patchUsed[128];
79 char drumUsed[128];
80 int a=0;
81
82 resetControllers();
83
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000084 for(a=0; a<128; a++)
85 {
86 patchSet[a]=NULL;
87 drumSet[a]=NULL;
88 patchUsed[a]=0;
89 drumUsed[a]=0;
90 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000091
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000092 /*
93 * Always load the piano.
94 * Some files will assume its loaded without specifically
95 * issuing a Patch command... then we wonder why we can't hear anything
96 */
97 patchUsed[0]=1;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +000098
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +000099 /* Scan the file to see what needs to be loaded */
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +0000100 if(mf != NULL)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000101 {
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +0000102 for(a=0; a<mf->numTracks; a++)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000103 {
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +0000104 unsigned int ts=0;
105
106 if(mf->tracks[a] == NULL)
107 {
108 printf("NULL TRACK !!!");
109 rb->splash(HZ*2, "Null Track in loader.");
110 return -1;
111 }
112
113 for(ts=0; ts<mf->tracks[a]->numEvents; ts++)
114 {
115
116 if((getEvent(mf->tracks[a], ts)->status) == (MIDI_NOTE_ON+9))
117 drumUsed[getEvent(mf->tracks[a], ts)->d1]=1;
118
119 if( (getEvent(mf->tracks[a], ts)->status & 0xF0) == MIDI_PRGM)
120 patchUsed[getEvent(mf->tracks[a], ts)->d1]=1;
121 }
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000122 }
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +0000123 } else
124 {
125 /* Initialize the whole drum set */
126 for(a=0; a<128; a++)
127 drumUsed[a]=1;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000128
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000129 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000130
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000131 int file = rb->open(filename, O_RDONLY);
Stepan Moskovchenko68af7ba2006-05-07 07:12:07 +0000132 if(file < 0)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000133 {
Jens Arnoldb1f00492007-04-21 05:35:17 +0000134 printf("");
135 printf("No MIDI patchset found.");
136 printf("Please install the instruments.");
137 printf("See Rockbox page for more info.");
Stepan Moskovchenko68af7ba2006-05-07 07:12:07 +0000138
Jens Arnold4d6374c2007-03-16 21:56:08 +0000139 rb->splash(HZ*2, "No Instruments");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000140 return -1;
141 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000142
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000143 char name[40];
144 char fn[40];
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000145
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000146 /* Scan our config file and load the right patches as needed */
147 int c = 0;
Jens Arnold79c8a8c2007-03-17 09:02:53 +0000148 name[0] = '\0';
Jens Arnoldb1f00492007-04-21 05:35:17 +0000149 printf("Loading instruments");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000150 for(a=0; a<128; a++)
151 {
152 while(readChar(file)!=' ' && !eof(file));
153 readTextBlock(file, name);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000154
Nils Wallménius04b34352007-09-10 09:46:36 +0000155 rb->snprintf(fn, 40, ROCKBOX_DIR "/patchset/%s.pat", name);
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000156/* printf("\nLOADING: <%s> ", fn); */
Stepan Moskovchenko58112142005-04-15 20:27:04 +0000157
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000158 if(patchUsed[a]==1)
159 {
160 patchSet[a]=gusload(fn);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000161
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000162 if(patchSet[a] == NULL) /* There was an error loading it */
163 return -1;
164 }
Stepan Moskovchenko58112142005-04-15 20:27:04 +0000165
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000166 while((c != '\n'))
167 c = readChar(file);
168 }
169 rb->close(file);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000170
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000171 file = rb->open(drumConfig, O_RDONLY);
Stepan Moskovchenko68af7ba2006-05-07 07:12:07 +0000172 if(file < 0)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000173 {
Jens Arnold4d6374c2007-03-16 21:56:08 +0000174 rb->splash(HZ*2, "Bad drum config. Did you install the patchset?");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000175 return -1;
176 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000177
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000178 /* Scan our config file and load the drum data */
179 int idx=0;
180 char number[30];
Jens Arnoldb1f00492007-04-21 05:35:17 +0000181 printf("Loading drums");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000182 while(!eof(file))
183 {
184 readTextBlock(file, number);
185 readTextBlock(file, name);
Nils Wallménius04b34352007-09-10 09:46:36 +0000186 rb->snprintf(fn, 40, ROCKBOX_DIR "/patchset/%s.pat", name);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000187
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000188 idx = rb->atoi(number);
189 if(idx == 0)
190 break;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000191
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000192 if(drumUsed[idx]==1)
193 {
194 drumSet[idx]=gusload(fn);
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000195 if(drumSet[idx] == NULL) /* Error loading patch */
196 return -1;
197 }
Stepan Moskovchenko58112142005-04-15 20:27:04 +0000198
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000199 while((c != '\n') && (c != 255) && (!eof(file)))
200 c = readChar(file);
201 }
202 rb->close(file);
203 return 0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000204}
205
Linus Nielsen Feltzing7c4b7862007-04-11 10:48:50 +0000206#define getSample(s,wf) ((short *)(wf)->data)[s]
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000207
Nils Wallménius6386dbe2007-09-30 11:21:25 +0000208void setPoint(struct SynthObject * so, int pt) ICODE_ATTR;
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000209void setPoint(struct SynthObject * so, int pt)
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000210{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000211 if(so->ch==9) /* Drums, no ADSR */
212 {
213 so->curOffset = 1<<27;
214 so->curRate = 1;
215 return;
216 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000217
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000218 if(so->wf==NULL)
219 {
Jens Arnoldb1f00492007-04-21 05:35:17 +0000220 printf("Crap... null waveform...");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000221 exit(1);
222 }
223 if(so->wf->envRate==NULL)
224 {
Jens Arnoldb1f00492007-04-21 05:35:17 +0000225 printf("Waveform has no envelope set");
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000226 exit(1);
227 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000228
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000229 so->curPoint = pt;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000230
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000231 int r;
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000232 int rate = so->wf->envRate[pt];
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000233
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000234 r=3-((rate>>6) & 0x3); /* Some blatant Timidity code for rate conversion... */
235 r*=3;
236 r = (rate & 0x3f) << r;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000237
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000238 /*
239 * Okay. This is the rate shift. Timidity defaults to 9, and sets
240 * it to 10 if you use the fast decay option. Slow decay sounds better
241 * on some files, except on some other files... you get chords that aren't
242 * done decaying yet.. and they dont harmonize with the next chord and it
243 * sounds like utter crap. Yes, even Timitidy does that. So I'm going to
244 * default this to 10, and maybe later have an option to set it to 9
245 * for longer decays.
246 */
Stepan Moskovchenko414724e2007-09-30 09:01:38 +0000247 so->curRate = r<<10;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000248
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000249 /*
250 * Do this here because the patches assume a 44100 sampling rate
251 * We've halved our sampling rate, ergo the ADSR code will be
252 * called half the time. Ergo, double the rate to keep stuff
253 * sounding right.
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000254 *
255 * Or just move the 1 up one line to optimize a tiny bit.
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000256 */
Stepan Moskovchenko94d9d152006-10-03 23:27:44 +0000257 /* so->curRate = so->curRate << 1; */
Stepan Moskovchenko1f5fb992005-04-19 15:57:07 +0000258
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000259
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000260 so->targetOffset = so->wf->envOffset[pt]<<(20);
261 if(pt==0)
262 so->curOffset = 0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000263}
264
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000265inline void stopVoice(struct SynthObject * so)
266{
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000267 if(so->state == STATE_RAMPDOWN)
268 return;
269 so->state = STATE_RAMPDOWN;
Stepan Moskovchenko80b48822006-10-02 04:13:33 +0000270 so->decay = 0;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000271}
272
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000273static inline void synthVoice(struct SynthObject * so, int32_t * out, unsigned int samples)
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000274{
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000275 struct GWaveform * wf;
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000276 register int s1;
277 register int s2;
278
279 register unsigned int cp_temp = so->cp;
Stepan Moskovchenkob2f1b5d2006-05-01 23:22:59 +0000280
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000281 wf = so->wf;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000282
Nils Wallménius0fd4c2e2007-11-11 01:02:45 +0000283 const unsigned int pan = chPan[so->ch];
284 const int volscale = so->volscale;
285
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000286 const int mode_mask24 = wf->mode&24;
287 const int mode_mask28 = wf->mode&28;
288 const int mode_mask_looprev = wf->mode&LOOP_REVERSE;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000289
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000290 const unsigned int num_samples = (wf->numSamples-1) << FRACTSIZE;
291
292 const unsigned int end_loop = wf->endLoop << FRACTSIZE;
293 const unsigned int start_loop = wf->startLoop << FRACTSIZE;
294 const int diff_loop = end_loop-start_loop;
295
Nils Wallménius0fd4c2e2007-11-11 01:02:45 +0000296 while(samples-- > 0)
Stepan Moskovchenko80b48822006-10-02 04:13:33 +0000297 {
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000298 /* Is voice being ramped? */
299 if(so->state == STATE_RAMPDOWN)
Stepan Moskovchenko80b48822006-10-02 04:13:33 +0000300 {
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000301 if(so->decay != 0) /* Ramp has been started */
302 {
303 so->decay = so->decay / 2;
Stepan Moskovchenko80b48822006-10-02 04:13:33 +0000304
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000305 if(so->decay < 10 && so->decay > -10)
Nils Wallménius0fd4c2e2007-11-11 01:02:45 +0000306 so->isUsed = false;
Stepan Moskovchenko80b48822006-10-02 04:13:33 +0000307
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000308 s1=so->decay;
Nils Wallménius0fd4c2e2007-11-11 01:02:45 +0000309 s2 = s1*pan;
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000310 s1 = (s1<<7) -s2;
Nils Wallménius0fd4c2e2007-11-11 01:02:45 +0000311 *(out++)+=((s1 << 9) & 0xFFFF0000) | ((s2 >> 7) &0xFFFF);
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000312 continue;
313 }
314 } else /* OK to advance voice */
315 {
316 cp_temp += so->delta;
Stepan Moskovchenko80b48822006-10-02 04:13:33 +0000317 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000318
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000319 s2 = getSample((cp_temp >> FRACTSIZE)+1, wf);
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000320
Nils Wallménius65331f12007-11-15 21:20:29 +0000321 if(mode_mask28)
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000322 {
Nils Wallménius65331f12007-11-15 21:20:29 +0000323 /* LOOP_REVERSE|LOOP_PINGPONG = 24 */
324 if(mode_mask24 && so->loopState == STATE_LOOPING && (cp_temp < start_loop))
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000325 {
Nils Wallménius65331f12007-11-15 21:20:29 +0000326 if(mode_mask_looprev)
Nils Wallménius0fd4c2e2007-11-11 01:02:45 +0000327 {
Nils Wallménius65331f12007-11-15 21:20:29 +0000328 cp_temp += diff_loop;
329 s2=getSample((cp_temp >> FRACTSIZE), wf);
330 }
331 else
332 {
333 so->delta = -so->delta; /* At this point cp_temp is wrong. We need to take a step */
334 }
335 }
336
337 if(cp_temp >= end_loop)
338 {
339 so->loopState = STATE_LOOPING;
340 if(!mode_mask24)
341 {
342 cp_temp -= diff_loop;
343 s2=getSample((cp_temp >> FRACTSIZE), wf);
344 }
345 else
346 {
347 so->delta = -so->delta;
Nils Wallménius0fd4c2e2007-11-11 01:02:45 +0000348 }
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000349 }
350 }
351
352 /* Have we overrun? */
353 if(cp_temp >= num_samples)
354 {
355 cp_temp -= so->delta;
356 s2 = getSample((cp_temp >> FRACTSIZE)+1, wf);
357 stopVoice(so);
358 }
359
360 /* Better, working, linear interpolation */
361 s1=getSample((cp_temp >> FRACTSIZE), wf);
362
Nils Wallménius0fd4c2e2007-11-11 01:02:45 +0000363 s1 +=((signed)((s2 - s1) * (cp_temp & ((1<<FRACTSIZE)-1)))>>FRACTSIZE);
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000364
365 if(so->curRate == 0)
366 {
367 stopVoice(so);
Nils Wallménius0fd4c2e2007-11-11 01:02:45 +0000368// so->isUsed = false;
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000369
370 }
371
372 if(so->ch != 9 && so->state != STATE_RAMPDOWN) /* Stupid ADSR code... and don't do ADSR for drums */
373 {
374 if(so->curOffset < so->targetOffset)
375 {
376 so->curOffset += (so->curRate);
377 if(so -> curOffset > so->targetOffset && so->curPoint != 2)
378 {
379 if(so->curPoint != 5)
380 {
381 setPoint(so, so->curPoint+1);
382 }
383 else
384 {
385 stopVoice(so);
386 }
387 }
388 } else
389 {
390 so->curOffset -= (so->curRate);
391 if(so -> curOffset < so->targetOffset && so->curPoint != 2)
392 {
393
394 if(so->curPoint != 5)
395 {
396 setPoint(so, so->curPoint+1);
397 }
398 else
399 {
400 stopVoice(so);
401 }
402
403 }
404 }
405 }
406
407 if(so->curOffset < 0)
408 {
409 so->curOffset = so->targetOffset;
410 stopVoice(so);
411 }
412
Nils Wallménius0fd4c2e2007-11-11 01:02:45 +0000413 s1 = s1 * (so->curOffset >> 22) >> 8;
414
415 /* Scaling by channel volume and note volume is done in sequencer.c */
416 /* That saves us some multiplication and pointer operations */
417 s1 = s1 * volscale >> 14;
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000418
419 /* need to set ramp beginning */
420 if(so->state == STATE_RAMPDOWN && so->decay == 0)
421 {
Nils Wallménius0fd4c2e2007-11-11 01:02:45 +0000422 so->decay = s1;
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000423 if(so->decay == 0)
424 so->decay = 1; /* stupid junk.. */
425 }
426
Nils Wallménius0fd4c2e2007-11-11 01:02:45 +0000427 s2 = s1*pan;
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000428 s1 = (s1<<7) - s2;
Nils Wallménius0fd4c2e2007-11-11 01:02:45 +0000429 *(out++)+=((s1 << 9) & 0xFFFF0000) | ((s2 >> 7) &0xFFFF);
Stepan Moskovchenko9ec1ff82005-04-20 21:07:13 +0000430 }
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000431
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000432 so->cp=cp_temp; /* store this again */
433 return;
Stepan Moskovchenko215e4922005-04-15 06:08:55 +0000434}
435
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000436/* buffer to hold all the samples for the current tick, this is a hack
437 neccesary for coldfire targets as pcm_play_data uses the dma which cannot
438 access iram */
Nils Wallménius2d91cf32007-10-21 22:50:10 +0000439int32_t samp_buf[512] IBSS_ATTR;
Stepan Moskovchenko1515ff82007-10-15 05:11:37 +0000440
Nils Wallméniusf619f812007-10-08 19:28:41 +0000441/* synth num_samples samples and write them to the */
442/* buffer pointed to by buf_ptr */
443void synthSamples(int32_t *buf_ptr, unsigned int num_samples) ICODE_ATTR;
444void synthSamples(int32_t *buf_ptr, unsigned int num_samples)
445{
Nils Wallménius2d91cf32007-10-21 22:50:10 +0000446 if (num_samples > 512)
447 DEBUGF("num_samples is too big!\n");
448 else
Nils Wallméniusf619f812007-10-08 19:28:41 +0000449 {
Nils Wallménius2d91cf32007-10-21 22:50:10 +0000450 int i;
451 struct SynthObject *voicept;
452
453 rb->memset(samp_buf, 0, num_samples*4);
454
455 for(i=0; i < MAX_VOICES; i++)
Nils Wallméniusf619f812007-10-08 19:28:41 +0000456 {
Nils Wallménius2d91cf32007-10-21 22:50:10 +0000457 voicept=&voices[i];
Nils Wallménius0fd4c2e2007-11-11 01:02:45 +0000458 if(voicept->isUsed)
Nils Wallménius2d91cf32007-10-21 22:50:10 +0000459 {
460 synthVoice(voicept, samp_buf, num_samples);
461 }
Nils Wallméniusf619f812007-10-08 19:28:41 +0000462 }
Nils Wallménius2d91cf32007-10-21 22:50:10 +0000463
464 rb->memcpy(buf_ptr, samp_buf, num_samples*4);
Nils Wallméniusf619f812007-10-08 19:28:41 +0000465 }
466 /* TODO: Automatic Gain Control, anyone? */
467 /* Or, should this be implemented on the DSP's output volume instead? */
468
469 return; /* No more ghetto lowpass filter. Linear interpolation works well. */
470}
471