cleaned all trailing white space from source files.
[sdk] / extras / audio / mixer.ec
1 public import "ecere"
2 import "audio"
3
4 #include <string.h>
5
6 // public define AUDIO_BUFFER_SIZE = 21024;
7 public define AUDIO_BUFFER_SIZE = 48000;
8
9 struct WAVEHDR
10 {
11    byte   format[4]           __attribute__((packed));
12    uint32 f_len               __attribute__((packed));
13    byte   wave_fmt[8]         __attribute__((packed));
14    uint32 fmt_len             __attribute__((packed));
15    uint16 fmt_tag             __attribute__((packed));
16    uint16 channel             __attribute__((packed));
17    uint32 samples_per_sec     __attribute__((packed));
18    uint32 avg_bytes_per_sec   __attribute__((packed));
19    uint16 blk_align           __attribute__((packed));
20    uint16 bits_per_sample     __attribute__((packed));
21    byte   data[4]             __attribute__((packed));
22    uint32 data_len            __attribute__((packed));
23 };
24
25 public class Sound
26 {
27 public:
28    property String fileName { set { Load(value); } }
29
30    int frequency, bits, channels, length;
31    byte * data;
32
33    ~Sound() { delete data; }
34
35    bool Load(char * fileName)
36    {
37       bool result = false;
38       WAVEHDR header;
39       File f = FileOpen(fileName, read);
40       if(f)
41       {
42          if(f.Read(header,sizeof(WAVEHDR),1) && !memcmp(header.format,"RIFF",4) && !memcmp(header.wave_fmt,"WAVEfmt ",8))
43          {
44             data = new byte[header.data_len];
45             if(data)
46             {
47                int c = f.Read(data, 1, header.data_len);
48                if(c)
49                {
50                   frequency = header.samples_per_sec;
51                   bits = header.bits_per_sample;
52                   channels = header.channel;
53                   length = Min(header.data_len, c);
54                   if(c < header.data_len)
55                      length -= 2048;
56
57                   if(bits == 16)
58                      length /= 2;
59                   result = true;
60                }
61             }
62          }
63          delete f;
64       }
65       return result;
66    }
67 }
68
69 public class Voice
70 {
71 public:
72    Sound sound;
73    double volume, balance, pitch;
74    int pos;
75    bool looped;
76    int loopStart, loopEnd;
77 }
78
79 public class Mixer
80 {
81    AudioSpec spec { };
82    Mutex mutex { };
83
84    ~Mixer()
85    {
86       CloseAudio();
87       while(voices.count)
88          voices.Delete((void *)voices.array);
89    }
90
91    void AudioCallback(byte *stream, int lenToFill)
92    {
93       static byte buffer[AUDIO_BUFFER_SIZE];
94       static float fBuffer[AUDIO_BUFFER_SIZE];
95       int c;
96       int numSamples = (bits == 16) ? (lenToFill / 2) : lenToFill;
97       memset(fBuffer, 0, sizeof(float) * numSamples);
98       mutex.Wait();
99       for(v : voices)
100       {
101          Sound sound = v.sound;
102          float volume = (float)v.volume;
103          float balance = (float)v.balance;
104          int freq = (int)(sound.frequency * v.pitch);
105          int chn = sound.channels;
106          if(sound.bits == 16)
107          {
108             short * sBuffer = sound.data;
109             int se = 0;
110             int s = v.pos;
111             short sampleL = sBuffer[s];
112             short sampleR = (chn == 2) ? sBuffer[s+1] : sampleL;
113
114             for(c = 0; c < numSamples; c++)
115             {
116                float left  = sampleL * volume / 32767.0f;
117                float right = sampleR * volume / 32767.0f;
118                if(balance)
119                {
120                   float v = balance * ((balance < 0) ? right : left);
121                   right += v;
122                   left  -= v;
123                }
124                if(channels == 2)
125                {
126                   fBuffer[c++] += left;
127                   fBuffer[c]   += right;
128                }
129                else
130                   fBuffer[c] += (left + right)/2;
131
132                se += freq;
133                if(se >= frequency)
134                {
135                   do
136                   {
137                      s += chn;
138                      se -= frequency;
139                   } while(se >= frequency);
140                   if(s < sound.length)
141                   {
142                      sampleL = sBuffer[s];
143                      sampleR = (chn == 2) ? sBuffer[s+1] : sampleL;
144                   }
145                   else
146                      break;
147                }
148             }
149             v.pos = s;
150          }
151          else if(sound.bits == 8)
152          {
153             byte * sBuffer = sound.data;
154             int se = 0;
155             int s = v.pos;
156             byte sampleL = sBuffer[s];
157             byte sampleR = (chn == 2) ? sBuffer[s+1] : sampleL;
158             bool looped = v.looped;
159             int loopStart = v.loopStart, loopEnd = v.loopEnd;
160
161             for(c = 0; c < numSamples; c++)
162             {
163                float left  = (sampleL - 127) * volume / 127.0f;
164                float right = (sampleR - 127) * volume / 127.0f;;
165                if(balance)
166                {
167                   float v = balance * ((balance < 0) ? right : left);
168                   right += v;
169                   left  -= v;
170                }
171                if(channels == 2)
172                {
173                   fBuffer[c++] += left;
174                   fBuffer[c]   += right;
175                }
176                else
177                   fBuffer[c] += (left + right)/2;
178
179                se += freq;
180                if(se >= frequency)
181                {
182                   do
183                   {
184                      s += chn;
185                      if(looped && s >= loopEnd)
186                         s = loopStart;
187                      se -= frequency;
188                   } while(se >= frequency);
189                   if(s < sound.length)
190                   {
191                      sampleL = sBuffer[s];
192                      sampleR = (chn == 2) ? sBuffer[s+1] : sampleL;
193                   }
194                   else
195                      break;
196                }
197             }
198             v.pos = s;
199          }
200       }
201       if(bits == 16)
202       {
203          for(c = 0; c < numSamples; c++)
204          {
205             int i = (int)(fBuffer[c] * 32767);
206             if(i > 32767) i = 32767; else if(i < -32768) i = -32768;
207             ((short *)buffer)[c] = (short)i;
208          }
209       }
210       else
211       {
212          for(c = 0; c < numSamples; c++)
213          {
214             int i = (int)(fBuffer[c] * 127) + 127;
215             if(i > 255) i = 255; else if(i < 0) i = 0;
216             buffer[c] = (byte)i;
217          }
218       }
219       memcpy(stream, buffer, lenToFill);
220       {
221          bool removed;
222          do
223          {
224             removed = false;
225             c = 0;
226             for(v : voices)
227             {
228                if(v.pos >= v.sound.length)
229                {
230                   removed = true;
231                   voices.Delete((void *)(voices.array + c));
232                   break;
233                }
234                c++;
235             }
236          } while(removed);
237       }
238       mutex.Release();
239    }
240
241 public:
242    void * systemHandle;
243    int frequency;
244    int bits;
245    int channels;
246    Array<Voice> voices { };
247
248    frequency = 44100;
249    bits = 16;
250    channels = 2;
251
252    property void * systemHandle { set { systemHandle = value; Init(); } }
253
254    bool Init()
255    {
256       AudioSpec wantedSpec
257       {
258          freq = frequency;
259          bits = bits;
260          channels = channels;
261          samples = AUDIO_BUFFER_SIZE;
262          callback = AudioCallback;
263          userdata = this;
264          windowHandle = systemHandle;
265          volume = 100;
266       };
267
268       if(!OpenAudio(wantedSpec, spec))
269       {
270          MessageBox { contents = "OpenAudio failed" }.Modal();
271          return false;
272       }
273       PauseAudio(0);
274       return true;
275    }
276
277    Voice Play(Sound sound, double volume, double balance, double pitch)
278    {
279       Voice voice { sound, volume, balance, pitch };
280       mutex.Wait();
281       voices.Add(voice);
282       incref voice;
283       mutex.Release();
284       return voice;
285    }
286
287    void Wait()
288    {
289       mutex.Wait();
290    }
291
292    void Release()
293    {
294       mutex.Release();
295    }
296
297    void PlayInVoice(Voice voice, Sound sound, double volume, double balance, double pitch)
298    {
299       bool found = false;
300       mutex.Wait();
301       for(v : voices)
302       {
303          if(v == voice)
304          {
305             found = true;
306             break;
307          }
308       }
309       if(!found)
310       {
311          voices.Add(voice);
312          incref voice;
313       }
314       voice.sound = sound;
315       voice.volume = volume;
316       voice.balance = balance;
317       voice.pitch = pitch;
318       voice.pos = 0;
319       mutex.Release();
320    }
321 }