annotate decoders/timidity/playmidi.c @ 474:c66080364dff

Most decoders now report total sample play time, now. Technically, this breaks binary compatibility with the 1.0 branch, since it extends the Sound_Sample struct, but most (all?) programs are just passing pointers allocated by SDL_sound around, and might be okay. Source-level compatibility is not broken...yet! :) --ryan. -------- Original Message -------- Subject: SDL_sound patch: Finding total length of time of sound file. Date: Sun, 26 Jan 2003 09:31:17 -0800 (PST) Hi Ryan, I am working with Eric Wing and helping him modify SDL_sound. AS part of our efforts in improving and enhancing SDL_sound, we like to submit this patch. We modified the codecs to find the total time of a sound file. Below is the explanation of the patch. The patch is appended as an attachment to this email. * MOTIVATION: We needed the ability to get the total play time of a sample (And we noticed that we're not the only ones). Since SDL_sound blocks direct access to the specific decoders, there is no way for a user to know this information short of decoding the whole thing. Because of this, we believe this will be a useful addition, even though the accuracy may not be perfect (subject to each decoder) or the information may not always be available. * CONTRIBUTORS: Wesley Leong (modified the majority of the codecs and verified the results) Eric Wing (showed everyone how to do modify codec, modified mikmod) Wang Lam (modified a handful of codecs, researched into specs and int overflow) Ahilan Anantha (modified a few codecs and helped with integer math) * GENERAL ISSUES: We chose the value to be milliseconds as an Sint32. Milliseconds because that's what Sound_Seek takes as a parameter and -1 to allow for instances/codecs where the value could not be determined. We are not sure if this is the final convention you want, so we are willing to work with you on this. We also expect the total_time field to be set on open and never again modified by SDL_sound. Users may access it directly much like the sample buffer and buffer_size. We thought about recomputing the time on DecodeAll, but since users may seek or decode small chunks first, not all the data may be there. So this is better done by the user. This may be good information to document. Currently, all the main codecs are implemented except for QuickTime.
author Ryan C. Gordon <icculus@icculus.org>
date Sat, 08 May 2004 08:19:50 +0000
parents cbc2a4ffeeec
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 }