diff options
Diffstat (limited to 'apps/plugins/midi/sequencer.c')
-rw-r--r-- | apps/plugins/midi/sequencer.c | 298 |
1 files changed, 298 insertions, 0 deletions
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 | } | ||