1 //metadoc AudioMixer copyright Steve Dekorte, 2002
2 //metadoc AudioMixer license All rights reserved. See _BSDLicense.txt.
4 #include "IoAudioMixer.h"
5 #include "IoAudioDevice.h"
6 #include "IoObject_actor.h"
8 #include "base/UArray.h"
17 #include "SoundTouch_wrapper.h"
19 /* 1/N of a second worth of frames/samples */
20 #define FRAMES_PER_BUFFER (44100/32)
24 AudioEvent
*AudioEvent_new(void)
26 AudioEvent
*self
= calloc(1, sizeof(AudioEvent
));
30 AudioEvent
*AudioEvent_newWithSound_onSample_of_type_(IoSound
*playSound
, long sample
, IoSound
*ioTriggerSound
, char etype
)
32 AudioEvent
*self
= AudioEvent_new();
33 self
->ioPlaySound
= playSound
;
34 self
->sample
= sample
- 1;
36 if (self
->sample
< 0) self
->sample
= 0;
37 self
->ioTriggerSound
= ioTriggerSound
;
41 void AudioEvent_free(AudioEvent
*self
)
46 void AudioEvent_mark(AudioEvent
*self
)
48 if (self
->ioTriggerSound
) IoObject_makeGrayIfWhite(self
->ioTriggerSound
);
49 if (self
->ioPlaySound
) IoObject_makeGrayIfWhite(self
->ioPlaySound
);
52 inline long AudioEvent_samplesUntilTrigger(AudioEvent
*self
)
54 if (!self
->ioTriggerSound
) return 0;
55 return self
->sample
- Sound_position(IoSound_rawSound(self
->ioTriggerSound
));
58 long AudioEvent_compare(AudioEvent
**self
, AudioEvent
**event
)
60 int diff
= AudioEvent_samplesUntilTrigger(*event
) - AudioEvent_samplesUntilTrigger(*self
);
61 if (diff
) return diff
;
62 return ((*self
)->etype
) == AUDIOEVENT_ADD
? 0 : 1;
65 void AudioEvent_show(AudioEvent
*self
)
67 char *type
= self
->etype
== AUDIOEVENT_ADD
? "add" : "remove";
69 printf("AudioEvent %p %s sound %p at sample %i\n",
70 (void *)self, type, self->ioPlaySound, (int)self->sample);
72 printf("event %s sound %p\n", type
, self
->ioPlaySound
);
76 /* ---------------------------------------------------------- */
78 #define DATA(self) ((IoAudioMixerData *)self->data)
80 IoTag
*IoAudioMixer_newTag(void *state
)
82 IoTag
*tag
= IoTag_newWithName_("AudioMixer");
83 IoTag_state_(tag
, state
);
84 IoTag_cloneFunc_(tag
, (IoTagCloneFunc
*)IoAudioMixer_rawClone
);
85 IoTag_freeFunc_(tag
, (IoTagFreeFunc
*)IoAudioMixer_free
);
86 IoTag_markFunc_(tag
, (IoTagMarkFunc
*)IoAudioMixer_mark
);
90 IoAudioMixer
*IoAudioMixer_proto(void *state
)
92 IoObject
*self
= IoObject_new(state
);
93 IoObject_tag_(self
, IoAudioMixer_newTag(state
));
95 self
->data
= calloc(1, sizeof(IoAudioMixerData
));
96 DATA(self
)->sounds
= List_new();
97 DATA(self
)->soundsToRemove
= List_new();
98 DATA(self
)->events
= List_new();
99 DATA(self
)->activeEvents
= List_new();
100 DATA(self
)->samplesPerBuffer
= FRAMES_PER_BUFFER
;
101 DATA(self
)->volume
= 1.0;
103 DATA(self
)->ioBuffer
= IoSeq_new(IOSTATE
);
104 DATA(self
)->buffer
= IoSeq_rawUArray(DATA(self
)->ioBuffer
);
105 DATA(self
)->mixBuffer
= UArray_new();
106 DATA(self
)->writeMessage
=
107 IoMessage_newWithName_label_(IOSTATE
,
109 IOSYMBOL("AudioMixer"));
110 IoMessage_setCachedArg_to_(DATA(self
)->writeMessage
, 0, DATA(self
)->ioBuffer
);
112 DATA(self
)->nonBlockingWriteMessage
=
113 IoMessage_newWithName_label_(IOSTATE
,
114 IOSYMBOL("nonBlockingWrite"),
115 IOSYMBOL("AudioMixer"));
116 IoMessage_setCachedArg_to_(DATA(self
)->nonBlockingWriteMessage
, 0, DATA(self
)->ioBuffer
);
118 DATA(self
)->soundTouch
= SoundTouch_init();
119 SoundTouch_setSampleRate(DATA(self
)->soundTouch
, 44100);
120 SoundTouch_setChannels(DATA(self
)->soundTouch
, 2);
121 DATA(self
)->tempo
= 1.0;
123 IoState_registerProtoWithFunc_(state
, self
, IoAudioMixer_proto
);
126 IoMethodTable methodTable
[] = {
127 {"start", IoAudioMixer_start
},
128 {"stop", IoAudioMixer_stop
},
129 {"sounds", IoAudioMixer_sounds
},
130 {"addSound", IoAudioMixer_addSound_
},
131 {"addSoundOnSampleOfSound",
132 IoAudioMixer_addSound_onSample_ofSound_
},
133 {"removeSound", IoAudioMixer_removeSound_
},
134 {"removeAllSounds", IoAudioMixer_removeAllSounds
},
135 {"removeSoundOnSampleOfSound", IoAudioMixer_removeSound_onSample_ofSound_
},
136 {"setSamplesPerBuffer", IoAudioMixer_setSamplesPerBuffer
},
137 {"setVolume", IoAudioMixer_setVolume
},
138 {"setTempo", IoAudioMixer_setTempo
},
139 {"setSampleRate", IoAudioMixer_setSampleRate
},
140 {"setPitchSemiTones", IoAudioMixer_setPitchSemiTones
},
141 {"setAudioDevice", IoAudioMixer_setAudioDevice
},
144 IoObject_addMethodTable_(self
, methodTable
);
147 DATA(self
)->ioAudioDevice
= IoObject_rawGetSlot_(self
, IOSYMBOL("AudioDevice"));
150 IOASSERT(DATA(self
)->ioAudioDevice
, "unable to find AudioDevice");
155 IoAudioMixer
*IoAudioMixer_rawClone(IoAudioMixer
*proto
)
157 IoObject
*self
= IoObject_rawClonePrimitive(proto
);
158 self
->data
= cpalloc(proto
->data
, sizeof(IoAudioMixerData
));
160 DATA(self
)->ioBuffer
= IoSeq_new(IOSTATE
);
161 DATA(self
)->buffer
= IoSeq_rawUArray(DATA(self
)->ioBuffer
);
162 DATA(proto
)->mixBuffer
= UArray_new();
163 DATA(self
)->writeMessage
=
164 IoMessage_newWithName_label_(IOSTATE
,
166 IOSYMBOL("AudioMixer"));
167 IoMessage_setCachedArg_to_(DATA(self
)->writeMessage
, 0, DATA(self
)->ioBuffer
);
169 DATA(self
)->nonBlockingWriteMessage
=
170 IoMessage_newWithName_label_(IOSTATE
,
171 IOSYMBOL("nonBlockingWrite"),
172 IOSYMBOL("AudioMixer"));
173 IoMessage_setCachedArg_to_(DATA(self
)->nonBlockingWriteMessage
, 0, DATA(self
)->ioBuffer
);
175 DATA(self
)->sounds
= List_new();
176 DATA(self
)->soundsToRemove
= List_new();
177 DATA(self
)->events
= List_new();
178 DATA(self
)->activeEvents
= List_new();
179 DATA(self
)->volume
= DATA(self
)->volume
;
181 DATA(self
)->soundTouch
= SoundTouch_init();
182 SoundTouch_setSampleRate(DATA(self
)->soundTouch
, 44100);
183 SoundTouch_setChannels(DATA(self
)->soundTouch
, 2);
184 DATA(self
)->tempo
= 1.0;
185 IoState_addValue_(IOSTATE
, self
);
189 IoAudioMixer
*IoAudioMixer_new(void *state
)
191 IoObject
*proto
= IoState_protoWithInitFunction_(state
, IoAudioMixer_proto
);
192 return IOCLONE(proto
);
195 /* ----------------------------------------------------------- */
197 void IoAudioMixer_free(IoAudioMixer
*self
)
199 List_free(DATA(self
)->sounds
);
200 List_free(DATA(self
)->soundsToRemove
);
201 List_free(DATA(self
)->events
);
202 List_free(DATA(self
)->activeEvents
);
203 UArray_free(DATA(self
)->mixBuffer
);
204 SoundTouch_free(DATA(self
)->soundTouch
);
208 void IoAudioMixer_mark(IoAudioMixer
*self
)
210 /* buffer is a UArray */
211 List_do_(DATA(self
)->sounds
, (ListDoCallback
*)IoObject_makeGrayIfWhite
);
212 List_do_(DATA(self
)->events
, (ListDoCallback
*)AudioEvent_mark
);
213 List_do_(DATA(self
)->activeEvents
, (ListDoCallback
*)AudioEvent_mark
);
214 List_do_(DATA(self
)->soundsToRemove
, (ListDoCallback
*)IoObject_makeGrayIfWhite
);
215 IoObject_makeGrayIfWhite(DATA(self
)->ioAudioDevice
);
216 IoObject_makeGrayIfWhite(DATA(self
)->writeMessage
);
217 IoObject_makeGrayIfWhite(DATA(self
)->nonBlockingWriteMessage
);
218 IoObject_makeGrayIfWhite(DATA(self
)->ioBuffer
);
221 /* ----------------------------------------------------------- */
223 void IoAudioMixer_updateBufferSize(IoAudioMixer
*self
)
225 int numBytes
= DATA(self
)->samplesPerBuffer
* sizeof(float) * 2;
226 UArray_setSize_(DATA(self
)->mixBuffer
, numBytes
* DATA(self
)->tempo
);
227 UArray_setSize_(DATA(self
)->buffer
, 10000*8);
230 IoObject
*IoAudioMixer_setAudioDevice(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
232 DATA(self
)->ioAudioDevice
= IOREF(IoMessage_locals_valueArgAt_(m
, locals
, 0));
236 IoObject
*IoAudioMixer_setSamplesPerBuffer(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
238 int s
= IoMessage_locals_intArgAt_(m
, locals
, 0);
239 DATA(self
)->samplesPerBuffer
= s
;
241 printf("IoAudioMixer_setSamplesPerBuffer(%i)\n", s
);
243 IoAudioMixer_updateBufferSize(self
);
247 void IoAudioMixer_updateScale(IoAudioMixer
*self
)
249 DATA(self
)->scale
= DATA(self
)->volume
* (float)(0.9 / sqrt((double)List_size(DATA(self
)->sounds
)));
252 IoObject
*IoAudioMixer_setVolume(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
254 DATA(self
)->volume
= IoMessage_locals_doubleArgAt_(m
, locals
, 0);
255 IoAudioMixer_updateScale(self
);
259 IoObject
*IoAudioMixer_sounds(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
261 IoList
*ioList
= IoList_new(IOSTATE
);
262 List_copy_(IoList_rawList(ioList
), DATA(self
)->sounds
);
266 void IoAudioMixer_showEvents(IoAudioMixer
*self
)
268 List
*events
= DATA(self
)->events
;
270 for (i
=0; i
<List_size(events
); i
++)
273 AudioEvent_show(List_at_(events
, i
));
275 /*List_do_(events, (ListDoCallback *)AudioEvent_show);*/
279 void IoAudioMixer_addEvent_(IoAudioMixer
*self
, AudioEvent
*event
)
281 List
*events
= DATA(self
)->events
;
282 List_append_(events
, event
);
283 List_qsort(events
, (void *)AudioEvent_compare
);
285 IoAudioMixer_showEvents(self
);
289 IoObject
*IoAudioMixer_addSound_(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
291 IoSound
*ioSound
= IoMessage_locals_soundArgAt_(m
, locals
, 0);
292 AudioEvent
*event
= AudioEvent_newWithSound_onSample_of_type_(ioSound
, 0, 0x0, AUDIOEVENT_ADD
);
293 IoAudioMixer_addEvent_(self
, event
);
297 IoObject
*IoAudioMixer_addSound_onSample_ofSound_(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
299 IoSound
*ioSound
= IoMessage_locals_soundArgAt_(m
, locals
, 0);
300 long sample
= IoMessage_locals_longArgAt_(m
, locals
, 1);
301 IoSound
*ioTriggerSound
= IoMessage_locals_soundArgAt_(m
, locals
, 2);
302 AudioEvent
*event
= AudioEvent_newWithSound_onSample_of_type_(
303 ioSound
, sample
, ioTriggerSound
, AUDIOEVENT_ADD
);
304 IoAudioMixer_addEvent_(self
, event
);
308 void IoAudioMixer_justAddSound_(IoAudioMixer
*self
, IoSound
*ioSound
)
310 /*printf("add sound %p\n", (void *)ioSound);*/
311 List_append_(DATA(self
)->sounds
, ioSound
);
312 Sound_setIsPlaying_(IoSound_rawSound(ioSound
), 1);
315 void IoAudioMixer_justRemoveSound_(IoAudioMixer
*self
, IoSound
*ioSound
)
317 /*printf("remove sound %p\n", (void *)ioSound);*/
318 List_remove_(DATA(self
)->sounds
, ioSound
);
319 Sound_setIsPlaying_(IoSound_rawSound(ioSound
), 0);
322 IoObject
*IoAudioMixer_removeSound_(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
324 IoSound
*ioSound
= IoMessage_locals_soundArgAt_(m
, locals
, 0);
325 /*List_append_(DATA(self)->soundsToRemove, ioSound);*/
326 AudioEvent
*event
= AudioEvent_newWithSound_onSample_of_type_(ioSound
, 0, 0x0, AUDIOEVENT_REMOVE
);
327 IoAudioMixer_addEvent_(self
, event
);
328 /*IoAudioMixer_justRemoveSound_(self, ioSound);*/
332 IoObject
*IoAudioMixer_removeAllSounds(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
334 List
*sounds
= DATA(self
)->sounds
;
335 while (List_size(sounds
))
337 IoAudioMixer_justRemoveSound_(self
, List_at_(sounds
, 0));
343 IoObject
*IoAudioMixer_removeSound_onSample_ofSound_(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
345 IoSound
*ioSound
= IoMessage_locals_soundArgAt_(m
, locals
, 0);
346 long sample
= IoMessage_locals_longArgAt_(m
, locals
, 1);
347 IoSound
*ioTriggerSound
= IoMessage_locals_soundArgAt_(m
, locals
, 2);
349 AudioEvent_newWithSound_onSample_of_type_(ioSound
, sample
, ioTriggerSound
, AUDIOEVENT_REMOVE
);
350 IoAudioMixer_addEvent_(self
, event
);
354 /* ----------------------------------------------------------- */
356 int IoAudioMixer_isActive(IoAudioMixer
*self
)
358 return List_size(DATA(self
)->sounds
) ||
359 List_size(DATA(self
)->soundsToRemove
) ||
360 List_size(DATA(self
)->events
) ||
361 List_size(DATA(self
)->activeEvents
);
364 IoObject
*IoAudioMixer_start(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
366 IoAudioMixer_updateBufferSize(self
);
368 DATA(self
)->isRunning
= 1;
369 while (DATA(self
)->isRunning
)
371 if (IoAudioMixer_isActive(self
))
373 int outSamples
= IoAudioMixer_mixOneChunk(self
, locals
, m
);
374 if (outSamples
< 5000)
377 printf("< 5000 out - mix another chunk\n");
379 IoAudioMixer_mixOneChunk(self
, locals
, m
);
382 //IoState_yield(IOSTATE);
387 IoObject
*IoAudioMixer_stop(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
389 DATA(self
)->isRunning
= 0;
390 /*IoAudioDevice_clearBuffers(DATA(self)->ioAudioDevice);*/
394 void IoAudioMixer_processSoundRemovals(IoAudioMixer
*self
)
397 List
*soundsToRemove
= DATA(self
)->soundsToRemove
;
398 List
*sounds
= DATA(self
)->sounds
;
399 int removeCount
= List_size(soundsToRemove
);
403 printf("removeCount = %i\n", removeCount
);
404 printf("soundsCount = %i\n", List_size(sounds
));
407 while ( (s
= List_pop(soundsToRemove
)) )
408 { IoAudioMixer_justRemoveSound_(self
, s
); }
412 printf("remaining sounds = %i\n", List_size(sounds
));
413 printf("remaining removeCount = %i\n\n", List_size(soundsToRemove
));
416 IoAudioMixer_updateScale(self
);
419 void IoAudioMixer_processActiveEvents(IoAudioMixer
*self
)
422 while ( (e
= List_pop(DATA(self
)->activeEvents
)) )
425 printf("processing: ");
431 IoAudioMixer_justAddSound_(self
, e
->ioPlaySound
);
433 case AUDIOEVENT_REMOVE
:
434 IoAudioMixer_justRemoveSound_(self
, e
->ioPlaySound
);
438 IoAudioMixer_updateScale(self
);
441 int IoAudioMixer_mixOneChunk(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
443 UArray
*mixBuffer
= DATA(self
)->mixBuffer
;
444 List
*sounds
= DATA(self
)->sounds
;
445 List
*soundsToRemove
= DATA(self
)->soundsToRemove
;
446 AudioEvent
*e
= List_top(DATA(self
)->events
);
447 List
*activeEvents
= DATA(self
)->activeEvents
;
449 /*int samplesPerBuffer = DATA(self)->samplesPerBuffer;*/
450 int samplesPerBuffer
= UArray_size(DATA(self
)->mixBuffer
) / (sizeof(float) * 2);
452 UArray_setAllBytesTo_(mixBuffer
, 0);
454 while ( e
&& (!e
->ioTriggerSound
))
456 List_append_(DATA(self
)->activeEvents
, List_pop(DATA(self
)->events
));
457 e
= List_top(DATA(self
)->events
);
460 if (List_size(activeEvents
)) IoAudioMixer_processActiveEvents(self
);
461 if (List_size(soundsToRemove
)) IoAudioMixer_processSoundRemovals(self
);
463 for (frame
= 0; frame
< samplesPerBuffer
; frame
++)
465 int index
= frame
* 2;
467 float *ol
= UArray_floatPointerAt_(mixBuffer
, index
);
468 float *or = UArray_floatPointerAt_(mixBuffer
, index
+1);
470 for (i
= 0; i
< List_size(sounds
); i
++)
472 IoSound
*ioSound
= List_at_(sounds
, i
);
473 Sound
*sound
= IoSound_rawSound(ioSound
);
475 char done
= Sound_nextFloat(sound
, &left
, &right
);
477 if (done
&& !Sound_isLooping(sound
))
479 List_append_(soundsToRemove
, ioSound
);
487 ((!e
->ioTriggerSound
) ||
488 ((e
->ioTriggerSound
== ioSound
) &&
489 (e
->sample
== Sound_position(sound
))))
492 List_append_(DATA(self
)->activeEvents
, List_pop(DATA(self
)->events
));
493 e
= List_top(DATA(self
)->events
);
497 (*ol
) *= DATA(self
)->scale
;
498 (*or) *= DATA(self
)->scale
;
500 if (List_size(activeEvents
)) IoAudioMixer_processActiveEvents(self
);
501 if (List_size(soundsToRemove
)) IoAudioMixer_processSoundRemovals(self
);
504 /* adjust pitch and tempo */
506 //double t1 = ((double)clock())/((double)CLOCKS_PER_SEC);
508 int receivedSamples
= 1;
510 SoundTouch_putSamples(DATA(self
)->soundTouch
, (float *)UArray_bytes(mixBuffer
), samplesPerBuffer
);
511 //printf("put %i\n", samplesPerBuffer);
512 //while (receivedSamples)
514 UArray_setSize_(DATA(self
)->buffer
, 10000*8);
515 receivedSamples
= SoundTouch_receiveSamples(DATA(self
)->soundTouch
,
516 (float *)UArray_bytes(DATA(self
)->buffer
),
517 UArray_size(DATA(self
)->buffer
) / (sizeof(float) * 2));
518 UArray_setSize_(DATA(self
)->buffer
, receivedSamples
* (sizeof(float) * 2));
520 //printf("received %i\n", receivedSamples);
523 if (receivedSamples
< 5000)
526 printf("non-blocking write\n");
529 IoMessage_locals_performOn_(DATA(self
)->nonBlockingWriteMessage
,
530 self
, DATA(self
)->ioAudioDevice
);
534 IoMessage_locals_performOn_(DATA(self
)->writeMessage
,
535 self
, DATA(self
)->ioAudioDevice
);
539 t2
= ((double)clock())/((double)CLOCKS_PER_SEC
);
540 printf("tempo: %1.1f %i -> %i in %0.2f sec\n",
549 return receivedSamples
;
551 /* need to change this to be dynamic, so we can easily record the output */
552 /*IoAudioDevice_justWrite(DATA(self)->ioAudioDevice, locals, m, buffer);*/
553 return UArray_size(DATA(self
)->buffer
) / 8;
556 IoObject
*IoAudioMixer_setTempo(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
558 DATA(self
)->tempo
= IoMessage_locals_floatArgAt_(m
, locals
, 0);
559 SoundTouch_setTempo(DATA(self
)->soundTouch
, DATA(self
)->tempo
);
560 printf("IoAudioMixer_setTempo(%f)\n", DATA(self
)->tempo
);
561 IoAudioMixer_updateBufferSize(self
);
565 IoObject
*IoAudioMixer_setSampleRate(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
567 DATA(self
)->sampleRate
= IoMessage_locals_intArgAt_(m
, locals
, 0);
568 SoundTouch_setSampleRate(DATA(self
)->soundTouch
, (unsigned int)DATA(self
)->sampleRate
);
569 printf("IoAudioMixer_setSampleRate(%i)\n", DATA(self
)->sampleRate
);
570 IoAudioMixer_updateBufferSize(self
);
574 IoObject
*IoAudioMixer_setPitchSemiTones(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
576 DATA(self
)->pitch
= IoMessage_locals_floatArgAt_(m
, locals
, 0);
577 SoundTouch_setPitchSemiTones(DATA(self
)->soundTouch
, DATA(self
)->pitch
);
578 printf("IoAudioMixer_setPitchSemiTones(%f)\n", DATA(self
)->pitch
);
579 IoAudioMixer_updateBufferSize(self
);