annotate decoders/timidity/playmidi.c @ 563:11bb8cb8ebc8

I think we can call playsound a 1.0 release by now. :)
author Ryan C. Gordon <icculus@icculus.org>
date Fri, 30 Jan 2009 02:45:38 -0500
parents c66080364dff
children
rev   line source
199
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
1 /*
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
2
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
3 TiMidity -- Experimental MIDI to WAVE converter
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
4 Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
5
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
6 This program is free software; you can redistribute it and/or modify
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
7 it under the terms of the GNU General Public License as published by
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
8 the Free Software Foundation; either version 2 of the License, or
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
9 (at your option) any later version.
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
10
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
11 This program is distributed in the hope that it will be useful,
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
14 GNU General Public License for more details.
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
15
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
16 You should have received a copy of the GNU General Public License
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
17 along with this program; if not, write to the Free Software
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
19
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
20 playmidi.c -- random stuff in need of rearrangement
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
21
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
22 */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
23
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
24 #if HAVE_CONFIG_H
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
25 # include <config.h>
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
26 #endif
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
27
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
28 #include <stdio.h>
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
29 #include <stdlib.h>
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
30 #include <string.h>
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
31
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
32 #include "SDL_sound.h"
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
33
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
34 #define __SDL_SOUND_INTERNAL__
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
35 #include "SDL_sound_internal.h"
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
36
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
37 #include "timidity.h"
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
38 #include "options.h"
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
39 #include "instrum.h"
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
40 #include "playmidi.h"
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
41 #include "output.h"
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
42 #include "mix.h"
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
43 #include "tables.h"
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
44
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
45 static void adjust_amplification(MidiSong *song)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
46 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
47 song->master_volume = (float)(song->amplification) / (float)100.0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
48 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
49
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
50 static void reset_voices(MidiSong *song)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
51 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
52 int i;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
53 for (i=0; i<MAX_VOICES; i++)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
54 song->voice[i].status=VOICE_FREE;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
55 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
56
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
57 /* Process the Reset All Controllers event */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
58 static void reset_controllers(MidiSong *song, int c)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
59 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
60 song->channel[c].volume=90; /* Some standard says, although the SCC docs say 0. */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
61 song->channel[c].expression=127; /* SCC-1 does this. */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
62 song->channel[c].sustain=0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
63 song->channel[c].pitchbend=0x2000;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
64 song->channel[c].pitchfactor=0; /* to be computed */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
65 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
66
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
67 static void reset_midi(MidiSong *song)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
68 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
69 int i;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
70 for (i=0; i<16; i++)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
71 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
72 reset_controllers(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
73 /* The rest of these are unaffected by the Reset All Controllers event */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
74 song->channel[i].program=song->default_program;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
75 song->channel[i].panning=NO_PANNING;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
76 song->channel[i].pitchsens=2;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
77 song->channel[i].bank=0; /* tone bank or drum set */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
78 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
79 reset_voices(song);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
80 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
81
455
cbc2a4ffeeec * Added support for loading DLS format instruments:
hercules
parents: 312
diff changeset
82 static void select_sample(MidiSong *song, int v, Instrument *ip, int vel)
199
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
83 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
84 Sint32 f, cdiff, diff;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
85 int s,i;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
86 Sample *sp, *closest;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
87
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
88 s=ip->samples;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
89 sp=ip->sample;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
90
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
91 if (s==1)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
92 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
93 song->voice[v].sample=sp;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
94 return;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
95 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
96
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
97 f=song->voice[v].orig_frequency;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
98 for (i=0; i<s; i++)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
99 {
455
cbc2a4ffeeec * Added support for loading DLS format instruments:
hercules
parents: 312
diff changeset
100 if (sp->low_vel <= vel && sp->high_vel >= vel &&
cbc2a4ffeeec * Added support for loading DLS format instruments:
hercules
parents: 312
diff changeset
101 sp->low_freq <= f && sp->high_freq >= f)
199
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
102 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
103 song->voice[v].sample=sp;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
104 return;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
105 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
106 sp++;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
107 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
108
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
109 /*
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
110 No suitable sample found! We'll select the sample whose root
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
111 frequency is closest to the one we want. (Actually we should
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
112 probably convert the low, high, and root frequencies to MIDI note
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
113 values and compare those.) */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
114
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
115 cdiff=0x7FFFFFFF;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
116 closest=sp=ip->sample;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
117 for(i=0; i<s; i++)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
118 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
119 diff=sp->root_freq - f;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
120 if (diff<0) diff=-diff;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
121 if (diff<cdiff)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
122 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
123 cdiff=diff;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
124 closest=sp;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
125 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
126 sp++;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
127 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
128 song->voice[v].sample=closest;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
129 return;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
130 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
131
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
132 static void recompute_freq(MidiSong *song, int v)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
133 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
134 int
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
135 sign=(song->voice[v].sample_increment < 0), /* for bidirectional loops */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
136 pb=song->channel[song->voice[v].channel].pitchbend;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
137 double a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
138
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
139 if (!song->voice[v].sample->sample_rate)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
140 return;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
141
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
142 if (song->voice[v].vibrato_control_ratio)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
143 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
144 /* This instrument has vibrato. Invalidate any precomputed
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
145 sample_increments. */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
146
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
147 int i=VIBRATO_SAMPLE_INCREMENTS;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
148 while (i--)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
149 song->voice[v].vibrato_sample_increment[i]=0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
150 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
151
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
152 if (pb==0x2000 || pb<0 || pb>0x3FFF)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
153 song->voice[v].frequency = song->voice[v].orig_frequency;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
154 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
155 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
156 pb-=0x2000;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
157 if (!(song->channel[song->voice[v].channel].pitchfactor))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
158 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
159 /* Damn. Somebody bent the pitch. */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
160 Sint32 i=pb*song->channel[song->voice[v].channel].pitchsens;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
161 if (pb<0)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
162 i=-i;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
163 song->channel[song->voice[v].channel].pitchfactor=
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
164 (float)(bend_fine[(i>>5) & 0xFF] * bend_coarse[i>>13]);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
165 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
166 if (pb>0)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
167 song->voice[v].frequency=
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
168 (Sint32)(song->channel[song->voice[v].channel].pitchfactor *
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
169 (double)(song->voice[v].orig_frequency));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
170 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
171 song->voice[v].frequency=
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
172 (Sint32)((double)(song->voice[v].orig_frequency) /
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
173 song->channel[song->voice[v].channel].pitchfactor);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
174 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
175
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
176 a = FSCALE(((double)(song->voice[v].sample->sample_rate) *
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
177 (double)(song->voice[v].frequency)) /
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
178 ((double)(song->voice[v].sample->root_freq) *
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
179 (double)(song->rate)),
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
180 FRACTION_BITS);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
181
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
182 if (sign)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
183 a = -a; /* need to preserve the loop direction */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
184
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
185 song->voice[v].sample_increment = (Sint32)(a);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
186 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
187
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
188 static void recompute_amp(MidiSong *song, int v)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
189 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
190 Sint32 tempamp;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
191
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
192 /* TODO: use fscale */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
193
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
194 tempamp= (song->voice[v].velocity *
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
195 song->channel[song->voice[v].channel].volume *
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
196 song->channel[song->voice[v].channel].expression); /* 21 bits */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
197
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
198 if (!(song->encoding & PE_MONO))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
199 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
200 if (song->voice[v].panning > 60 && song->voice[v].panning < 68)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
201 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
202 song->voice[v].panned=PANNED_CENTER;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
203
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
204 song->voice[v].left_amp=
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
205 FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
206 21);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
207 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
208 else if (song->voice[v].panning<5)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
209 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
210 song->voice[v].panned = PANNED_LEFT;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
211
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
212 song->voice[v].left_amp=
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
213 FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
214 20);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
215 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
216 else if (song->voice[v].panning>123)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
217 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
218 song->voice[v].panned = PANNED_RIGHT;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
219
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
220 song->voice[v].left_amp= /* left_amp will be used */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
221 FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
222 20);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
223 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
224 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
225 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
226 song->voice[v].panned = PANNED_MYSTERY;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
227
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
228 song->voice[v].left_amp=
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
229 FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
230 27);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
231 song->voice[v].right_amp = song->voice[v].left_amp * (song->voice[v].panning);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
232 song->voice[v].left_amp *= (float)(127 - song->voice[v].panning);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
233 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
234 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
235 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
236 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
237 song->voice[v].panned = PANNED_CENTER;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
238
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
239 song->voice[v].left_amp=
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
240 FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
241 21);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
242 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
243 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
244
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
245 static void start_note(MidiSong *song, MidiEvent *e, int i)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
246 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
247 Instrument *ip;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
248 int j;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
249
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
250 if (ISDRUMCHANNEL(song, e->channel))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
251 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
252 if (!(ip=song->drumset[song->channel[e->channel].bank]->instrument[e->a]))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
253 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
254 if (!(ip=song->drumset[0]->instrument[e->a]))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
255 return; /* No instrument? Then we can't play. */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
256 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
257 if (ip->samples != 1)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
258 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
259 SNDDBG(("Strange: percussion instrument with %d samples!",
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
260 ip->samples));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
261 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
262
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
263 if (ip->sample->note_to_use) /* Do we have a fixed pitch? */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
264 song->voice[i].orig_frequency = freq_table[(int)(ip->sample->note_to_use)];
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
265 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
266 song->voice[i].orig_frequency = freq_table[e->a & 0x7F];
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
267
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
268 /* drums are supposed to have only one sample */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
269 song->voice[i].sample = ip->sample;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
270 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
271 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
272 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
273 if (song->channel[e->channel].program == SPECIAL_PROGRAM)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
274 ip=song->default_instrument;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
275 else if (!(ip=song->tonebank[song->channel[e->channel].bank]->
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
276 instrument[song->channel[e->channel].program]))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
277 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
278 if (!(ip=song->tonebank[0]->instrument[song->channel[e->channel].program]))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
279 return; /* No instrument? Then we can't play. */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
280 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
281
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
282 if (ip->sample->note_to_use) /* Fixed-pitch instrument? */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
283 song->voice[i].orig_frequency = freq_table[(int)(ip->sample->note_to_use)];
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
284 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
285 song->voice[i].orig_frequency = freq_table[e->a & 0x7F];
455
cbc2a4ffeeec * Added support for loading DLS format instruments:
hercules
parents: 312
diff changeset
286 select_sample(song, i, ip, e->b);
199
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
287 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
288
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
289 song->voice[i].status = VOICE_ON;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
290 song->voice[i].channel = e->channel;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
291 song->voice[i].note = e->a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
292 song->voice[i].velocity = e->b;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
293 song->voice[i].sample_offset = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
294 song->voice[i].sample_increment = 0; /* make sure it isn't negative */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
295
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
296 song->voice[i].tremolo_phase = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
297 song->voice[i].tremolo_phase_increment = song->voice[i].sample->tremolo_phase_increment;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
298 song->voice[i].tremolo_sweep = song->voice[i].sample->tremolo_sweep_increment;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
299 song->voice[i].tremolo_sweep_position = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
300
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
301 song->voice[i].vibrato_sweep = song->voice[i].sample->vibrato_sweep_increment;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
302 song->voice[i].vibrato_sweep_position = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
303 song->voice[i].vibrato_control_ratio = song->voice[i].sample->vibrato_control_ratio;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
304 song->voice[i].vibrato_control_counter = song->voice[i].vibrato_phase = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
305 for (j=0; j<VIBRATO_SAMPLE_INCREMENTS; j++)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
306 song->voice[i].vibrato_sample_increment[j] = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
307
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
308 if (song->channel[e->channel].panning != NO_PANNING)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
309 song->voice[i].panning = song->channel[e->channel].panning;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
310 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
311 song->voice[i].panning = song->voice[i].sample->panning;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
312
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
313 recompute_freq(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
314 recompute_amp(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
315 if (song->voice[i].sample->modes & MODES_ENVELOPE)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
316 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
317 /* Ramp up from 0 */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
318 song->voice[i].envelope_stage = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
319 song->voice[i].envelope_volume = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
320 song->voice[i].control_counter = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
321 recompute_envelope(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
322 apply_envelope_to_amp(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
323 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
324 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
325 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
326 song->voice[i].envelope_increment = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
327 apply_envelope_to_amp(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
328 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
329 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
330
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
331 static void kill_note(MidiSong *song, int i)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
332 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
333 song->voice[i].status = VOICE_DIE;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
334 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
335
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
336 /* Only one instance of a note can be playing on a single channel. */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
337 static void note_on(MidiSong *song)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
338 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
339 int i = song->voices, lowest=-1;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
340 Sint32 lv=0x7FFFFFFF, v;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
341 MidiEvent *e = song->current_event;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
342
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
343 while (i--)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
344 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
345 if (song->voice[i].status == VOICE_FREE)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
346 lowest=i; /* Can't get a lower volume than silence */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
347 else if (song->voice[i].channel==e->channel &&
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
348 (song->voice[i].note==e->a || song->channel[song->voice[i].channel].mono))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
349 kill_note(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
350 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
351
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
352 if (lowest != -1)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
353 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
354 /* Found a free voice. */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
355 start_note(song,e,lowest);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
356 return;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
357 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
358
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
359 /* Look for the decaying note with the lowest volume */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
360 i = song->voices;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
361 while (i--)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
362 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
363 if ((song->voice[i].status != VOICE_ON) &&
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
364 (song->voice[i].status != VOICE_DIE))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
365 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
366 v = song->voice[i].left_mix;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
367 if ((song->voice[i].panned == PANNED_MYSTERY)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
368 && (song->voice[i].right_mix > v))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
369 v = song->voice[i].right_mix;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
370 if (v<lv)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
371 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
372 lv=v;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
373 lowest=i;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
374 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
375 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
376 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
377
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
378 if (lowest != -1)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
379 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
380 /* This can still cause a click, but if we had a free voice to
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
381 spare for ramping down this note, we wouldn't need to kill it
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
382 in the first place... Still, this needs to be fixed. Perhaps
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
383 we could use a reserve of voices to play dying notes only. */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
384
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
385 song->cut_notes++;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
386 song->voice[lowest].status=VOICE_FREE;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
387 start_note(song,e,lowest);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
388 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
389 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
390 song->lost_notes++;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
391 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
392
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
393 static void finish_note(MidiSong *song, int i)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
394 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
395 if (song->voice[i].sample->modes & MODES_ENVELOPE)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
396 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
397 /* We need to get the envelope out of Sustain stage */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
398 song->voice[i].envelope_stage = 3;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
399 song->voice[i].status = VOICE_OFF;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
400 recompute_envelope(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
401 apply_envelope_to_amp(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
402 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
403 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
404 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
405 /* Set status to OFF so resample_voice() will let this voice out
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
406 of its loop, if any. In any case, this voice dies when it
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
407 hits the end of its data (ofs>=data_length). */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
408 song->voice[i].status = VOICE_OFF;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
409 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
410 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
411
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
412 static void note_off(MidiSong *song)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
413 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
414 int i = song->voices;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
415 MidiEvent *e = song->current_event;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
416
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
417 while (i--)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
418 if (song->voice[i].status == VOICE_ON &&
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
419 song->voice[i].channel == e->channel &&
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
420 song->voice[i].note == e->a)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
421 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
422 if (song->channel[e->channel].sustain)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
423 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
424 song->voice[i].status = VOICE_SUSTAINED;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
425 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
426 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
427 finish_note(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
428 return;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
429 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
430 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
431
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
432 /* Process the All Notes Off event */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
433 static void all_notes_off(MidiSong *song)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
434 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
435 int i = song->voices;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
436 int c = song->current_event->channel;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
437
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
438 SNDDBG(("All notes off on channel %d", c));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
439 while (i--)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
440 if (song->voice[i].status == VOICE_ON &&
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
441 song->voice[i].channel == c)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
442 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
443 if (song->channel[c].sustain)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
444 song->voice[i].status = VOICE_SUSTAINED;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
445 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
446 finish_note(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
447 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
448 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
449
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
450 /* Process the All Sounds Off event */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
451 static void all_sounds_off(MidiSong *song)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
452 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
453 int i = song->voices;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
454 int c = song->current_event->channel;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
455
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
456 while (i--)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
457 if (song->voice[i].channel == c &&
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
458 song->voice[i].status != VOICE_FREE &&
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
459 song->voice[i].status != VOICE_DIE)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
460 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
461 kill_note(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
462 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
463 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
464
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
465 static void adjust_pressure(MidiSong *song)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
466 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
467 MidiEvent *e = song->current_event;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
468 int i = song->voices;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
469
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
470 while (i--)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
471 if (song->voice[i].status == VOICE_ON &&
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
472 song->voice[i].channel == e->channel &&
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
473 song->voice[i].note == e->a)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
474 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
475 song->voice[i].velocity = e->b;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
476 recompute_amp(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
477 apply_envelope_to_amp(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
478 return;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
479 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
480 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
481
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
482 static void drop_sustain(MidiSong *song)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
483 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
484 int i = song->voices;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
485 int c = song->current_event->channel;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
486
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
487 while (i--)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
488 if (song->voice[i].status == VOICE_SUSTAINED && song->voice[i].channel == c)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
489 finish_note(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
490 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
491
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
492 static void adjust_pitchbend(MidiSong *song)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
493 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
494 int c = song->current_event->channel;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
495 int i = song->voices;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
496
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
497 while (i--)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
498 if (song->voice[i].status != VOICE_FREE && song->voice[i].channel == c)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
499 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
500 recompute_freq(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
501 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
502 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
503
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
504 static void adjust_volume(MidiSong *song)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
505 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
506 int c = song->current_event->channel;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
507 int i = song->voices;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
508
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
509 while (i--)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
510 if (song->voice[i].channel == c &&
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
511 (song->voice[i].status==VOICE_ON || song->voice[i].status==VOICE_SUSTAINED))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
512 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
513 recompute_amp(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
514 apply_envelope_to_amp(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
515 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
516 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
517
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
518 static void seek_forward(MidiSong *song, Sint32 until_time)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
519 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
520 reset_voices(song);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
521 while (song->current_event->time < until_time)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
522 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
523 switch(song->current_event->type)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
524 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
525 /* All notes stay off. Just handle the parameter changes. */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
526
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
527 case ME_PITCH_SENS:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
528 song->channel[song->current_event->channel].pitchsens =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
529 song->current_event->a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
530 song->channel[song->current_event->channel].pitchfactor = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
531 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
532
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
533 case ME_PITCHWHEEL:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
534 song->channel[song->current_event->channel].pitchbend =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
535 song->current_event->a + song->current_event->b * 128;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
536 song->channel[song->current_event->channel].pitchfactor = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
537 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
538
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
539 case ME_MAINVOLUME:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
540 song->channel[song->current_event->channel].volume =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
541 song->current_event->a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
542 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
543
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
544 case ME_PAN:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
545 song->channel[song->current_event->channel].panning =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
546 song->current_event->a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
547 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
548
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
549 case ME_EXPRESSION:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
550 song->channel[song->current_event->channel].expression =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
551 song->current_event->a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
552 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
553
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
554 case ME_PROGRAM:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
555 if (ISDRUMCHANNEL(song, song->current_event->channel))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
556 /* Change drum set */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
557 song->channel[song->current_event->channel].bank =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
558 song->current_event->a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
559 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
560 song->channel[song->current_event->channel].program =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
561 song->current_event->a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
562 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
563
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
564 case ME_SUSTAIN:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
565 song->channel[song->current_event->channel].sustain =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
566 song->current_event->a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
567 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
568
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
569 case ME_RESET_CONTROLLERS:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
570 reset_controllers(song, song->current_event->channel);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
571 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
572
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
573 case ME_TONE_BANK:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
574 song->channel[song->current_event->channel].bank =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
575 song->current_event->a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
576 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
577
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
578 case ME_EOT:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
579 song->current_sample = song->current_event->time;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
580 return;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
581 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
582 song->current_event++;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
583 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
584 /*song->current_sample=song->current_event->time;*/
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
585 if (song->current_event != song->events)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
586 song->current_event--;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
587 song->current_sample=until_time;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
588 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
589
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
590 static void skip_to(MidiSong *song, Sint32 until_time)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
591 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
592 if (song->current_sample > until_time)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
593 song->current_sample = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
594
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
595 reset_midi(song);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
596 song->buffered_count = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
597 song->buffer_pointer = song->common_buffer;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
598 song->current_event = song->events;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
599
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
600 if (until_time)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
601 seek_forward(song, until_time);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
602 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
603
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
604 static void do_compute_data(MidiSong *song, Sint32 count)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
605 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
606 int i;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
607 memset(song->buffer_pointer, 0,
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
608 (song->encoding & PE_MONO) ? (count * 4) : (count * 8));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
609 for (i = 0; i < song->voices; i++)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
610 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
611 if(song->voice[i].status != VOICE_FREE)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
612 mix_voice(song, song->buffer_pointer, i, count);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
613 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
614 song->current_sample += count;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
615 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
616
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
617 /* count=0 means flush remaining buffered data to output device, then
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
618 flush the device itself */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
619 static void compute_data(MidiSong *song, void *stream, Sint32 count)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
620 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
621 int channels;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
622
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
623 if ( song->encoding & PE_MONO )
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
624 channels = 1;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
625 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
626 channels = 2;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
627
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
628 if (!count)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
629 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
630 if (song->buffered_count)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
631 song->write(stream, song->common_buffer, channels * song->buffered_count);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
632 song->buffer_pointer = song->common_buffer;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
633 song->buffered_count = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
634 return;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
635 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
636
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
637 while ((count + song->buffered_count) >= song->buffer_size)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
638 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
639 do_compute_data(song, song->buffer_size - song->buffered_count);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
640 count -= song->buffer_size - song->buffered_count;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
641 song->write(stream, song->common_buffer, channels * song->buffer_size);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
642 song->buffer_pointer = song->common_buffer;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
643 song->buffered_count = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
644 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
645 if (count>0)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
646 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
647 do_compute_data(song, count);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
648 song->buffered_count += count;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
649 song->buffer_pointer += (song->encoding & PE_MONO) ? count : count*2;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
650 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
651 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
652
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
653 void Timidity_Start(MidiSong *song)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
654 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
655 song->playing = 1;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
656 adjust_amplification(song);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
657 skip_to(song, 0);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
658 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
659
312
498240aa76f1 Seek implementations.
Ryan C. Gordon <icculus@icculus.org>
parents: 199
diff changeset
660 void Timidity_Seek(MidiSong *song, Uint32 ms)
498240aa76f1 Seek implementations.
Ryan C. Gordon <icculus@icculus.org>
parents: 199
diff changeset
661 {
498240aa76f1 Seek implementations.
Ryan C. Gordon <icculus@icculus.org>
parents: 199
diff changeset
662 skip_to(song, (ms * song->rate) / 1000);
498240aa76f1 Seek implementations.
Ryan C. Gordon <icculus@icculus.org>
parents: 199
diff changeset
663 }
498240aa76f1 Seek implementations.
Ryan C. Gordon <icculus@icculus.org>
parents: 199
diff changeset
664
474
c66080364dff Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents: 455
diff changeset
665 Uint32 Timidity_GetSongLength(MidiSong *song)
c66080364dff Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents: 455
diff changeset
666 {
c66080364dff Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents: 455
diff changeset
667 MidiEvent *last_event = &song->events[song->groomed_event_count - 1];
c66080364dff Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents: 455
diff changeset
668 /* We want last_event->time * 1000 / song->rate */
c66080364dff Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents: 455
diff changeset
669 Uint32 retvalue = (last_event->time / song->rate) * 1000;
c66080364dff Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents: 455
diff changeset
670 retvalue += (last_event->time % song->rate) * 1000 / song->rate;
c66080364dff Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents: 455
diff changeset
671 return retvalue;
c66080364dff Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents: 455
diff changeset
672 }
c66080364dff Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents: 455
diff changeset
673
199
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
674 int Timidity_PlaySome(MidiSong *song, void *stream, Sint32 len)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
675 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
676 Sint32 start_sample, end_sample, samples;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
677 int bytes_per_sample;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
678
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
679 if (!song->playing)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
680 return 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
681
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
682 bytes_per_sample =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
683 ((song->encoding & PE_MONO) ? 1 : 2)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
684 * ((song->encoding & PE_16BIT) ? 2 : 1);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
685 samples = len / bytes_per_sample;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
686
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
687 start_sample = song->current_sample;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
688 end_sample = song->current_sample+samples;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
689 while ( song->current_sample < end_sample ) {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
690 /* Handle all events that should happen at this time */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
691 while (song->current_event->time <= song->current_sample) {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
692 switch(song->current_event->type) {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
693
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
694 /* Effects affecting a single note */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
695
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
696 case ME_NOTEON:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
697 if (!(song->current_event->b)) /* Velocity 0? */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
698 note_off(song);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
699 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
700 note_on(song);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
701 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
702
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
703 case ME_NOTEOFF:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
704 note_off(song);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
705 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
706
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
707 case ME_KEYPRESSURE:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
708 adjust_pressure(song);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
709 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
710
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
711 /* Effects affecting a single channel */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
712
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
713 case ME_PITCH_SENS:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
714 song->channel[song->current_event->channel].pitchsens =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
715 song->current_event->a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
716 song->channel[song->current_event->channel].pitchfactor = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
717 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
718
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
719 case ME_PITCHWHEEL:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
720 song->channel[song->current_event->channel].pitchbend =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
721 song->current_event->a + song->current_event->b * 128;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
722 song->channel[song->current_event->channel].pitchfactor = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
723 /* Adjust pitch for notes already playing */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
724 adjust_pitchbend(song);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
725 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
726
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
727 case ME_MAINVOLUME:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
728 song->channel[song->current_event->channel].volume =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
729 song->current_event->a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
730 adjust_volume(song);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
731 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
732
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
733 case ME_PAN:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
734 song->channel[song->current_event->channel].panning =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
735 song->current_event->a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
736 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
737
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
738 case ME_EXPRESSION:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
739 song->channel[song->current_event->channel].expression =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
740 song->current_event->a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
741 adjust_volume(song);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
742 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
743
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
744 case ME_PROGRAM:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
745 if (ISDRUMCHANNEL(song, song->current_event->channel)) {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
746 /* Change drum set */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
747 song->channel[song->current_event->channel].bank =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
748 song->current_event->a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
749 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
750 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
751 song->channel[song->current_event->channel].program =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
752 song->current_event->a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
753 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
754
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
755 case ME_SUSTAIN:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
756 song->channel[song->current_event->channel].sustain =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
757 song->current_event->a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
758 if (!song->current_event->a)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
759 drop_sustain(song);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
760 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
761
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
762 case ME_RESET_CONTROLLERS:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
763 reset_controllers(song, song->current_event->channel);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
764 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
765
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
766 case ME_ALL_NOTES_OFF:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
767 all_notes_off(song);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
768 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
769
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
770 case ME_ALL_SOUNDS_OFF:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
771 all_sounds_off(song);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
772 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
773
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
774 case ME_TONE_BANK:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
775 song->channel[song->current_event->channel].bank =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
776 song->current_event->a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
777 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
778
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
779 case ME_EOT:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
780 /* Give the last notes a couple of seconds to decay */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
781 SNDDBG(("Playing time: ~%d seconds\n",
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
782 song->current_sample/song->rate+2));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
783 SNDDBG(("Notes cut: %d\n", song->cut_notes));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
784 SNDDBG(("Notes lost totally: %d\n", song->lost_notes));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
785 song->playing = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
786 return (song->current_sample - start_sample) * bytes_per_sample;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
787 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
788 song->current_event++;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
789 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
790 if (song->current_event->time > end_sample)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
791 compute_data(song, stream, end_sample-song->current_sample);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
792 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
793 compute_data(song, stream, song->current_event->time-song->current_sample);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
794 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
795 return samples * bytes_per_sample;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
796 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
797
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
798 void Timidity_SetVolume(MidiSong *song, int volume)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
799 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
800 int i;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
801 if (volume > MAX_AMPLIFICATION)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
802 song->amplification = MAX_AMPLIFICATION;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
803 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
804 if (volume < 0)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
805 song->amplification = 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
806 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
807 song->amplification = volume;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
808 adjust_amplification(song);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
809 for (i = 0; i < song->voices; i++)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
810 if (song->voice[i].status != VOICE_FREE)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
811 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
812 recompute_amp(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
813 apply_envelope_to_amp(song, i);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
814 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
815 }