summaryrefslogtreecommitdiff
path: root/apps/plugins/midi/synth.c
diff options
context:
space:
mode:
authorStepan Moskovchenko <stevenm@rockbox.org>2007-10-15 05:11:37 +0000
committerStepan Moskovchenko <stevenm@rockbox.org>2007-10-15 05:11:37 +0000
commit1515ff852224c822a6d3db8c458eab2c9037704f (patch)
treee427fbec1b397d18abffc12b7fe74e67c2cad807 /apps/plugins/midi/synth.c
parent99f955088149d5938ce4c9ca5624377f464b1380 (diff)
downloadrockbox-1515ff852224c822a6d3db8c458eab2c9037704f.zip
rockbox-1515ff852224c822a6d3db8c458eab2c9037704f.tar.gz
rockbox-1515ff852224c822a6d3db8c458eab2c9037704f.tar.bz2
rockbox-1515ff852224c822a6d3db8c458eab2c9037704f.tar.xz
MIDI: At long last, though quick and dirty, pitch bend depth! Or, I think it works. Tested on two
files. Let me know if anyone discovers any problems with this. This commit also includes Nils's synth loop optimization patch. I hope committing it does not cause problems. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15112 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/midi/synth.c')
-rw-r--r--apps/plugins/midi/synth.c261
1 files changed, 133 insertions, 128 deletions
diff --git a/apps/plugins/midi/synth.c b/apps/plugins/midi/synth.c
index 568c7bb..f0fa93d 100644
--- a/apps/plugins/midi/synth.c
+++ b/apps/plugins/midi/synth.c
@@ -65,6 +65,7 @@ int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig)
chPan[a]=64; /* Center */
chPat[a]=0; /* Ac Gr Piano */
chPW[a]=256; /* .. not .. bent ? */
+ chPBDepth[a]=2; /* Default bend value is 2 */
}
for(a=0; a<128; a++)
{
@@ -255,191 +256,195 @@ inline void stopVoice(struct SynthObject * so)
so->decay = 0;
}
-static inline int synthVoice(struct SynthObject * so)
+static inline void synthVoice(struct SynthObject * so, int32_t * out, unsigned int samples)
{
struct GWaveform * wf;
register int s;
- register unsigned int cpShifted;
- register short s1;
- register short s2;
+ register int s1;
+ register int s2;
+
+ register unsigned int cp_temp = so->cp;
wf = so->wf;
+ const int mode_mask24 = wf->mode&24;
+ const int mode_mask28 = wf->mode&28;
+ const int mode_mask_looprev = wf->mode&LOOP_REVERSE;
- /* Is voice being ramped? */
- if(so->state == STATE_RAMPDOWN)
- {
- if(so->decay != 0) /* Ramp has been started */
- {
- so->decay = so->decay / 2;
+ const unsigned int num_samples = (wf->numSamples-1) << FRACTSIZE;
- if(so->decay < 10 && so->decay > -10)
- so->isUsed = 0;
+ const unsigned int end_loop = wf->endLoop << FRACTSIZE;
+ const unsigned int start_loop = wf->startLoop << FRACTSIZE;
+ const int diff_loop = end_loop-start_loop;
- return so->decay;
- }
- } else /* OK to advance voice */
+ while(samples > 0)
{
- so->cp += so->delta;
- }
-
-
- cpShifted = so->cp >> FRACTSIZE;
+ samples--;
+ /* Is voice being ramped? */
+ if(so->state == STATE_RAMPDOWN)
+ {
+ if(so->decay != 0) /* Ramp has been started */
+ {
+ so->decay = so->decay / 2;
+ if(so->decay < 10 && so->decay > -10)
+ so->isUsed = 0;
+ s1=so->decay;
+ s2 = s1*chPan[so->ch];
+ s1 = (s1<<7) -s2;
+ *(out++)+=(((s1&0x7FFF80) << 9) | ((s2&0x7FFF80) >> 7));
+ continue;
+ }
+ } else /* OK to advance voice */
+ {
+ cp_temp += so->delta;
+ }
- s2 = getSample((cpShifted)+1, wf);
+ s2 = getSample((cp_temp >> FRACTSIZE)+1, wf);
/* LOOP_REVERSE|LOOP_PINGPONG = 24 */
- if((wf->mode & (24)) && so->loopState == STATE_LOOPING && (cpShifted < (wf->startLoop)))
- {
- if(wf->mode & LOOP_REVERSE)
- {
- cpShifted = wf->endLoop-(wf->startLoop-cpShifted);
- so->cp = (cpShifted)<<FRACTSIZE;
- s2=getSample((cpShifted), wf);
- }
- else
+ if(mode_mask24 && so->loopState == STATE_LOOPING && (cp_temp < start_loop))
{
- so->delta = -so->delta; /* At this point cpShifted is wrong. We need to take a step */
- so->loopDir = LOOPDIR_FORWARD;
+ if(mode_mask_looprev)
+ {
+ cp_temp += diff_loop;
+ s2=getSample((cp_temp >> FRACTSIZE), wf);
+ }
+ else
+ {
+ so->delta = -so->delta; /* At this point cp_temp is wrong. We need to take a step */
+ so->loopDir = LOOPDIR_FORWARD;
+ }
}
- }
- if((wf->mode & 28) && (cpShifted >= wf->endLoop))
- {
- so->loopState = STATE_LOOPING;
- if((wf->mode & (24)) == 0)
+ if(mode_mask28 && (cp_temp >= end_loop))
{
- cpShifted = wf->startLoop + (cpShifted-wf->endLoop);
- so->cp = (cpShifted)<<FRACTSIZE;
- s2=getSample((cpShifted), wf);
+ so->loopState = STATE_LOOPING;
+ if(!mode_mask24)
+ {
+ cp_temp -= diff_loop;
+ s2=getSample((cp_temp >> FRACTSIZE), wf);
+ }
+ else
+ {
+ so->delta = -so->delta;
+ so->loopDir = LOOPDIR_REVERSE;
+ }
}
- else
+
+ /* Have we overrun? */
+ if(cp_temp >= num_samples)
{
- so->delta = -so->delta;
- so->loopDir = LOOPDIR_REVERSE;
+ cp_temp -= so->delta;
+ s2 = getSample((cp_temp >> FRACTSIZE)+1, wf);
+ stopVoice(so);
}
- }
-
- /* Have we overrun? */
- if( (cpShifted >= (wf->numSamples-1)))
- {
- so->cp -= so->delta;
- cpShifted = so->cp >> FRACTSIZE;
- s2 = getSample((cpShifted)+1, wf);
- stopVoice(so);
- }
-
-
- /* Better, working, linear interpolation */
- s1=getSample((cpShifted), wf);
- s = s1 + ((signed)((s2 - s1) * (so->cp & ((1<<FRACTSIZE)-1)))>>FRACTSIZE);
+ /* Better, working, linear interpolation */
+ s1=getSample((cp_temp >> FRACTSIZE), wf);
+ s = s1 + ((signed)((s2 - s1) * (cp_temp & ((1<<FRACTSIZE)-1)))>>FRACTSIZE);
- if(so->curRate == 0)
- {
- stopVoice(so);
-// so->isUsed = 0;
+ if(so->curRate == 0)
+ {
+ stopVoice(so);
+// so->isUsed = 0;
- }
+ }
- if(so->ch != 9 && so->state != STATE_RAMPDOWN) /* Stupid ADSR code... and don't do ADSR for drums */
- {
- if(so->curOffset < so->targetOffset)
+ if(so->ch != 9 && so->state != STATE_RAMPDOWN) /* Stupid ADSR code... and don't do ADSR for drums */
{
- so->curOffset += (so->curRate);
- if(so -> curOffset > so->targetOffset && so->curPoint != 2)
+ if(so->curOffset < so->targetOffset)
{
- if(so->curPoint != 5)
+ so->curOffset += (so->curRate);
+ if(so -> curOffset > so->targetOffset && so->curPoint != 2)
{
- setPoint(so, so->curPoint+1);
+ if(so->curPoint != 5)
+ {
+ setPoint(so, so->curPoint+1);
+ }
+ else
+ {
+ stopVoice(so);
+ }
}
- else
+ } else
+ {
+ so->curOffset -= (so->curRate);
+ if(so -> curOffset < so->targetOffset && so->curPoint != 2)
{
- stopVoice(so);
+
+ if(so->curPoint != 5)
+ {
+ setPoint(so, so->curPoint+1);
+ }
+ else
+ {
+ stopVoice(so);
+ }
+
}
}
- } else
+ }
+
+ if(so->curOffset < 0)
{
- so->curOffset -= (so->curRate);
- if(so -> curOffset < so->targetOffset && so->curPoint != 2)
- {
+ so->curOffset = so->targetOffset;
+ stopVoice(so);
+ }
- if(so->curPoint != 5)
- {
- setPoint(so, so->curPoint+1);
- }
- else
- {
- stopVoice(so);
- }
+ s = (s * (so->curOffset >> 22) >> 8);
- }
+ /* need to set ramp beginning */
+ if(so->state == STATE_RAMPDOWN && so->decay == 0)
+ {
+ so->decay = s*so->volscale>>14;
+ if(so->decay == 0)
+ so->decay = 1; /* stupid junk.. */
}
- }
- if(so->curOffset < 0)
- {
- so->curOffset = so->targetOffset;
- stopVoice(so);
- }
- s = (s * (so->curOffset >> 22) >> 8);
+ /* Scaling by channel volume and note volume is done in sequencer.c */
+ /* That saves us some multiplication and pointer operations */
+ s1=s*so->volscale>>14;
+ s2 = s1*chPan[so->ch];
+ s1 = (s1<<7) - s2;
+ *(out++)+=(((s1&0x7FFF80) << 9) | ((s2&0x7FFF80) >> 7));
- /* need to set ramp beginning */
- if(so->state == STATE_RAMPDOWN && so->decay == 0)
- {
- so->decay = s*so->volscale>>14;
- if(so->decay == 0)
- so->decay = 1; /* stupid junk.. */
}
-
- /* Scaling by channel volume and note volume is done in sequencer.c */
- /* That saves us some multiplication and pointer operations */
- return s*so->volscale>>14;
+ so->cp=cp_temp; /* store this again */
+ return;
}
+/* buffer to hold all the samples for the current tick, this is a hack
+ neccesary for coldfire targets as pcm_play_data uses the dma which cannot
+ access iram */
+int32_t samp_buf[256] IBSS_ATTR;
+
/* synth num_samples samples and write them to the */
/* buffer pointed to by buf_ptr */
void synthSamples(int32_t *buf_ptr, unsigned int num_samples) ICODE_ATTR;
void synthSamples(int32_t *buf_ptr, unsigned int num_samples)
{
int i;
- register int dL;
- register int dR;
- register int sample;
- register struct SynthObject *voicept;
- while(num_samples>0)
- {
- dL=0;
- dR=0;
- voicept=&voices[0];
+ struct SynthObject *voicept;
+
+ rb->memset(samp_buf, 0, num_samples*4);
- for(i=MAX_VOICES; i > 0; i--)
+ for(i=0; i < MAX_VOICES; i++)
+ {
+ voicept=&voices[i];
+ if(voicept->isUsed==1)
{
- if(voicept->isUsed==1)
- {
- sample = synthVoice(voicept);
- dL += sample;
- sample *= chPan[voicept->ch];
- dR += sample;
- }
- voicept++;
+ synthVoice(voicept, samp_buf, num_samples);
}
+ }
- dL = (dL << 7) - dR;
-
- /* combine the left and right 16 bit samples into 32 bits and write */
- /* to the buffer, left sample in the high word and right in the low word */
- *buf_ptr=(((dL&0x7FFF80) << 9) | ((dR&0x7FFF80) >> 7));
+ rb->memcpy(buf_ptr, samp_buf, num_samples*4);
- buf_ptr++;
- num_samples--;
- }
/* TODO: Automatic Gain Control, anyone? */
/* Or, should this be implemented on the DSP's output volume instead? */