1 /* copyright: Steve Dekorte, 2002
2 * All rights reserved. See _BSDLicense.txt.
5 #include "IoAudioMixer.h"
6 #include "IoAudioDevice.h"
7 #include "IoObject_actor.h"
9 #include "base/UArray.h"
18 #include "SoundTouch_wrapper.h"
20 /* 1/N of a second worth of frames/samples */
21 #define FRAMES_PER_BUFFER (44100/32)
25 AudioEvent
*AudioEvent_new(void)
27 AudioEvent
*self
= calloc(1, sizeof(AudioEvent
));
31 AudioEvent
*AudioEvent_newWithSound_onSample_of_type_(IoSound
*playSound
, long sample
, IoSound
*ioTriggerSound
, char etype
)
33 AudioEvent
*self
= AudioEvent_new();
34 self
->ioPlaySound
= playSound
;
35 self
->sample
= sample
- 1;
37 if (self
->sample
< 0) self
->sample
= 0;
38 self
->ioTriggerSound
= ioTriggerSound
;
42 void AudioEvent_free(AudioEvent
*self
)
47 void AudioEvent_mark(AudioEvent
*self
)
49 if (self
->ioTriggerSound
) IoObject_makeGrayIfWhite(self
->ioTriggerSound
);
50 if (self
->ioPlaySound
) IoObject_makeGrayIfWhite(self
->ioPlaySound
);
53 inline long AudioEvent_samplesUntilTrigger(AudioEvent
*self
)
55 if (!self
->ioTriggerSound
) return 0;
56 return self
->sample
- Sound_position(IoSound_rawSound(self
->ioTriggerSound
));
59 long AudioEvent_compare(AudioEvent
**self
, AudioEvent
**event
)
61 int diff
= AudioEvent_samplesUntilTrigger(*event
) - AudioEvent_samplesUntilTrigger(*self
);
62 if (diff
) return diff
;
63 return ((*self
)->etype
) == AUDIOEVENT_ADD
? 0 : 1;
66 void AudioEvent_show(AudioEvent
*self
)
68 char *type
= self
->etype
== AUDIOEVENT_ADD
? "add" : "remove";
70 printf("AudioEvent %p %s sound %p at sample %i\n",
71 (void *)self, type, self->ioPlaySound, (int)self->sample);
73 printf("event %s sound %p\n", type
, self
->ioPlaySound
);
77 /* ---------------------------------------------------------- */
79 #define DATA(self) ((IoAudioMixerData *)self->data)
81 IoTag
*IoAudioMixer_newTag(void *state
)
83 IoTag
*tag
= IoTag_newWithName_("AudioMixer");
84 IoTag_state_(tag
, state
);
85 IoTag_cloneFunc_(tag
, (IoTagCloneFunc
*)IoAudioMixer_rawClone
);
86 IoTag_freeFunc_(tag
, (IoTagFreeFunc
*)IoAudioMixer_free
);
87 IoTag_markFunc_(tag
, (IoTagMarkFunc
*)IoAudioMixer_mark
);
91 IoAudioMixer
*IoAudioMixer_proto(void *state
)
93 IoObject
*self
= IoObject_new(state
);
94 IoObject_tag_(self
, IoAudioMixer_newTag(state
));
96 self
->data
= calloc(1, sizeof(IoAudioMixerData
));
97 DATA(self
)->sounds
= List_new();
98 DATA(self
)->soundsToRemove
= List_new();
99 DATA(self
)->events
= List_new();
100 DATA(self
)->activeEvents
= List_new();
101 DATA(self
)->samplesPerBuffer
= FRAMES_PER_BUFFER
;
102 DATA(self
)->volume
= 1.0;
104 DATA(self
)->ioBuffer
= IoSeq_new(IOSTATE
);
105 DATA(self
)->buffer
= IoSeq_rawUArray(DATA(self
)->ioBuffer
);
106 DATA(self
)->mixBuffer
= UArray_new();
107 DATA(self
)->writeMessage
=
108 IoMessage_newWithName_label_(IOSTATE
,
110 IOSYMBOL("AudioMixer"));
111 IoMessage_setCachedArg_to_(DATA(self
)->writeMessage
, 0, DATA(self
)->ioBuffer
);
113 DATA(self
)->nonBlockingWriteMessage
=
114 IoMessage_newWithName_label_(IOSTATE
,
115 IOSYMBOL("nonBlockingWrite"),
116 IOSYMBOL("AudioMixer"));
117 IoMessage_setCachedArg_to_(DATA(self
)->nonBlockingWriteMessage
, 0, DATA(self
)->ioBuffer
);
119 DATA(self
)->soundTouch
= SoundTouch_init();
120 SoundTouch_setSampleRate(DATA(self
)->soundTouch
, 44100);
121 SoundTouch_setChannels(DATA(self
)->soundTouch
, 2);
122 DATA(self
)->tempo
= 1.0;
124 IoState_registerProtoWithFunc_(state
, self
, IoAudioMixer_proto
);
127 IoMethodTable methodTable
[] = {
128 {"start", IoAudioMixer_start
},
129 {"stop", IoAudioMixer_stop
},
130 {"sounds", IoAudioMixer_sounds
},
131 {"addSound", IoAudioMixer_addSound_
},
132 {"addSoundOnSampleOfSound",
133 IoAudioMixer_addSound_onSample_ofSound_
},
134 {"removeSound", IoAudioMixer_removeSound_
},
135 {"removeAllSounds", IoAudioMixer_removeAllSounds
},
136 {"removeSoundOnSampleOfSound", IoAudioMixer_removeSound_onSample_ofSound_
},
137 {"setSamplesPerBuffer", IoAudioMixer_setSamplesPerBuffer
},
138 {"setVolume", IoAudioMixer_setVolume
},
139 {"setTempo", IoAudioMixer_setTempo
},
140 {"setSampleRate", IoAudioMixer_setSampleRate
},
141 {"setPitchSemiTones", IoAudioMixer_setPitchSemiTones
},
142 {"setAudioDevice", IoAudioMixer_setAudioDevice
},
145 IoObject_addMethodTable_(self
, methodTable
);
148 DATA(self
)->ioAudioDevice
= IoObject_rawGetSlot_(self
, IOSYMBOL("AudioDevice"));
151 IOASSERT(DATA(self
)->ioAudioDevice
, "unable to find AudioDevice");
156 IoAudioMixer
*IoAudioMixer_rawClone(IoAudioMixer
*proto
)
158 IoObject
*self
= IoObject_rawClonePrimitive(proto
);
159 self
->data
= cpalloc(proto
->data
, sizeof(IoAudioMixerData
));
161 DATA(self
)->ioBuffer
= IoSeq_new(IOSTATE
);
162 DATA(self
)->buffer
= IoSeq_rawUArray(DATA(self
)->ioBuffer
);
163 DATA(proto
)->mixBuffer
= UArray_new();
164 DATA(self
)->writeMessage
=
165 IoMessage_newWithName_label_(IOSTATE
,
167 IOSYMBOL("AudioMixer"));
168 IoMessage_setCachedArg_to_(DATA(self
)->writeMessage
, 0, DATA(self
)->ioBuffer
);
170 DATA(self
)->nonBlockingWriteMessage
=
171 IoMessage_newWithName_label_(IOSTATE
,
172 IOSYMBOL("nonBlockingWrite"),
173 IOSYMBOL("AudioMixer"));
174 IoMessage_setCachedArg_to_(DATA(self
)->nonBlockingWriteMessage
, 0, DATA(self
)->ioBuffer
);
176 DATA(self
)->sounds
= List_new();
177 DATA(self
)->soundsToRemove
= List_new();
178 DATA(self
)->events
= List_new();
179 DATA(self
)->activeEvents
= List_new();
180 DATA(self
)->volume
= DATA(self
)->volume
;
182 DATA(self
)->soundTouch
= SoundTouch_init();
183 SoundTouch_setSampleRate(DATA(self
)->soundTouch
, 44100);
184 SoundTouch_setChannels(DATA(self
)->soundTouch
, 2);
185 DATA(self
)->tempo
= 1.0;
186 IoState_addValue_(IOSTATE
, self
);
190 IoAudioMixer
*IoAudioMixer_new(void *state
)
192 IoObject
*proto
= IoState_protoWithInitFunction_(state
, IoAudioMixer_proto
);
193 return IOCLONE(proto
);
196 /* ----------------------------------------------------------- */
198 void IoAudioMixer_free(IoAudioMixer
*self
)
200 List_free(DATA(self
)->sounds
);
201 List_free(DATA(self
)->soundsToRemove
);
202 List_free(DATA(self
)->events
);
203 List_free(DATA(self
)->activeEvents
);
204 UArray_free(DATA(self
)->mixBuffer
);
205 SoundTouch_free(DATA(self
)->soundTouch
);
209 void IoAudioMixer_mark(IoAudioMixer
*self
)
211 /* buffer is a UArray */
212 List_do_(DATA(self
)->sounds
, (ListDoCallback
*)IoObject_makeGrayIfWhite
);
213 List_do_(DATA(self
)->events
, (ListDoCallback
*)AudioEvent_mark
);
214 List_do_(DATA(self
)->activeEvents
, (ListDoCallback
*)AudioEvent_mark
);
215 List_do_(DATA(self
)->soundsToRemove
, (ListDoCallback
*)IoObject_makeGrayIfWhite
);
216 IoObject_makeGrayIfWhite(DATA(self
)->ioAudioDevice
);
217 IoObject_makeGrayIfWhite(DATA(self
)->writeMessage
);
218 IoObject_makeGrayIfWhite(DATA(self
)->nonBlockingWriteMessage
);
219 IoObject_makeGrayIfWhite(DATA(self
)->ioBuffer
);
222 /* ----------------------------------------------------------- */
224 void IoAudioMixer_updateBufferSize(IoAudioMixer
*self
)
226 int numBytes
= DATA(self
)->samplesPerBuffer
* sizeof(float) * 2;
227 UArray_setSize_(DATA(self
)->mixBuffer
, numBytes
* DATA(self
)->tempo
);
228 UArray_setSize_(DATA(self
)->buffer
, 10000*8);
231 IoObject
*IoAudioMixer_setAudioDevice(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
233 DATA(self
)->ioAudioDevice
= IOREF(IoMessage_locals_valueArgAt_(m
, locals
, 0));
237 IoObject
*IoAudioMixer_setSamplesPerBuffer(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
239 int s
= IoMessage_locals_intArgAt_(m
, locals
, 0);
240 DATA(self
)->samplesPerBuffer
= s
;
242 printf("IoAudioMixer_setSamplesPerBuffer(%i)\n", s
);
244 IoAudioMixer_updateBufferSize(self
);
248 void IoAudioMixer_updateScale(IoAudioMixer
*self
)
250 DATA(self
)->scale
= DATA(self
)->volume
* (float)(0.9 / sqrt((double)List_size(DATA(self
)->sounds
)));
253 IoObject
*IoAudioMixer_setVolume(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
255 DATA(self
)->volume
= IoMessage_locals_doubleArgAt_(m
, locals
, 0);
256 IoAudioMixer_updateScale(self
);
260 IoObject
*IoAudioMixer_sounds(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
262 IoList
*ioList
= IoList_new(IOSTATE
);
263 List_copy_(IoList_rawList(ioList
), DATA(self
)->sounds
);
267 void IoAudioMixer_showEvents(IoAudioMixer
*self
)
269 List
*events
= DATA(self
)->events
;
271 for (i
=0; i
<List_size(events
); i
++)
274 AudioEvent_show(List_at_(events
, i
));
276 /*List_do_(events, (ListDoCallback *)AudioEvent_show);*/
280 void IoAudioMixer_addEvent_(IoAudioMixer
*self
, AudioEvent
*event
)
282 List
*events
= DATA(self
)->events
;
283 List_append_(events
, event
);
284 List_qsort(events
, (void *)AudioEvent_compare
);
286 IoAudioMixer_showEvents(self
);
290 IoObject
*IoAudioMixer_addSound_(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
292 IoSound
*ioSound
= IoMessage_locals_soundArgAt_(m
, locals
, 0);
293 AudioEvent
*event
= AudioEvent_newWithSound_onSample_of_type_(ioSound
, 0, 0x0, AUDIOEVENT_ADD
);
294 IoAudioMixer_addEvent_(self
, event
);
298 IoObject
*IoAudioMixer_addSound_onSample_ofSound_(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
300 IoSound
*ioSound
= IoMessage_locals_soundArgAt_(m
, locals
, 0);
301 long sample
= IoMessage_locals_longArgAt_(m
, locals
, 1);
302 IoSound
*ioTriggerSound
= IoMessage_locals_soundArgAt_(m
, locals
, 2);
303 AudioEvent
*event
= AudioEvent_newWithSound_onSample_of_type_(
304 ioSound
, sample
, ioTriggerSound
, AUDIOEVENT_ADD
);
305 IoAudioMixer_addEvent_(self
, event
);
309 void IoAudioMixer_justAddSound_(IoAudioMixer
*self
, IoSound
*ioSound
)
311 /*printf("add sound %p\n", (void *)ioSound);*/
312 List_append_(DATA(self
)->sounds
, ioSound
);
313 Sound_setIsPlaying_(IoSound_rawSound(ioSound
), 1);
316 void IoAudioMixer_justRemoveSound_(IoAudioMixer
*self
, IoSound
*ioSound
)
318 /*printf("remove sound %p\n", (void *)ioSound);*/
319 List_remove_(DATA(self
)->sounds
, ioSound
);
320 Sound_setIsPlaying_(IoSound_rawSound(ioSound
), 0);
323 IoObject
*IoAudioMixer_removeSound_(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
325 IoSound
*ioSound
= IoMessage_locals_soundArgAt_(m
, locals
, 0);
326 /*List_append_(DATA(self)->soundsToRemove, ioSound);*/
327 AudioEvent
*event
= AudioEvent_newWithSound_onSample_of_type_(ioSound
, 0, 0x0, AUDIOEVENT_REMOVE
);
328 IoAudioMixer_addEvent_(self
, event
);
329 /*IoAudioMixer_justRemoveSound_(self, ioSound);*/
333 IoObject
*IoAudioMixer_removeAllSounds(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
335 List
*sounds
= DATA(self
)->sounds
;
336 while (List_size(sounds
))
338 IoAudioMixer_justRemoveSound_(self
, List_at_(sounds
, 0));
344 IoObject
*IoAudioMixer_removeSound_onSample_ofSound_(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
346 IoSound
*ioSound
= IoMessage_locals_soundArgAt_(m
, locals
, 0);
347 long sample
= IoMessage_locals_longArgAt_(m
, locals
, 1);
348 IoSound
*ioTriggerSound
= IoMessage_locals_soundArgAt_(m
, locals
, 2);
350 AudioEvent_newWithSound_onSample_of_type_(ioSound
, sample
, ioTriggerSound
, AUDIOEVENT_REMOVE
);
351 IoAudioMixer_addEvent_(self
, event
);
355 /* ----------------------------------------------------------- */
357 int IoAudioMixer_isActive(IoAudioMixer
*self
)
359 return List_size(DATA(self
)->sounds
) ||
360 List_size(DATA(self
)->soundsToRemove
) ||
361 List_size(DATA(self
)->events
) ||
362 List_size(DATA(self
)->activeEvents
);
365 IoObject
*IoAudioMixer_start(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
367 IoAudioMixer_updateBufferSize(self
);
369 DATA(self
)->isRunning
= 1;
370 while (DATA(self
)->isRunning
)
372 if (IoAudioMixer_isActive(self
))
374 int outSamples
= IoAudioMixer_mixOneChunk(self
, locals
, m
);
375 if (outSamples
< 5000)
378 printf("< 5000 out - mix another chunk\n");
380 IoAudioMixer_mixOneChunk(self
, locals
, m
);
383 //IoState_yield(IOSTATE);
388 IoObject
*IoAudioMixer_stop(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
390 DATA(self
)->isRunning
= 0;
391 /*IoAudioDevice_clearBuffers(DATA(self)->ioAudioDevice);*/
395 void IoAudioMixer_processSoundRemovals(IoAudioMixer
*self
)
398 List
*soundsToRemove
= DATA(self
)->soundsToRemove
;
399 List
*sounds
= DATA(self
)->sounds
;
400 int removeCount
= List_size(soundsToRemove
);
404 printf("removeCount = %i\n", removeCount
);
405 printf("soundsCount = %i\n", List_size(sounds
));
408 while ( (s
= List_pop(soundsToRemove
)) )
409 { IoAudioMixer_justRemoveSound_(self
, s
); }
413 printf("remaining sounds = %i\n", List_size(sounds
));
414 printf("remaining removeCount = %i\n\n", List_size(soundsToRemove
));
417 IoAudioMixer_updateScale(self
);
420 void IoAudioMixer_processActiveEvents(IoAudioMixer
*self
)
423 while ( (e
= List_pop(DATA(self
)->activeEvents
)) )
426 printf("processing: ");
432 IoAudioMixer_justAddSound_(self
, e
->ioPlaySound
);
434 case AUDIOEVENT_REMOVE
:
435 IoAudioMixer_justRemoveSound_(self
, e
->ioPlaySound
);
439 IoAudioMixer_updateScale(self
);
442 int IoAudioMixer_mixOneChunk(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
444 UArray
*mixBuffer
= DATA(self
)->mixBuffer
;
445 List
*sounds
= DATA(self
)->sounds
;
446 List
*soundsToRemove
= DATA(self
)->soundsToRemove
;
447 AudioEvent
*e
= List_top(DATA(self
)->events
);
448 List
*activeEvents
= DATA(self
)->activeEvents
;
450 /*int samplesPerBuffer = DATA(self)->samplesPerBuffer;*/
451 int samplesPerBuffer
= UArray_size(DATA(self
)->mixBuffer
) / (sizeof(float) * 2);
453 UArray_setAllBytesTo_(mixBuffer
, 0);
455 while ( e
&& (!e
->ioTriggerSound
))
457 List_append_(DATA(self
)->activeEvents
, List_pop(DATA(self
)->events
));
458 e
= List_top(DATA(self
)->events
);
461 if (List_size(activeEvents
)) IoAudioMixer_processActiveEvents(self
);
462 if (List_size(soundsToRemove
)) IoAudioMixer_processSoundRemovals(self
);
464 for (frame
= 0; frame
< samplesPerBuffer
; frame
++)
466 int index
= frame
* 2;
468 float *ol
= UArray_floatPointerAt_(mixBuffer
, index
);
469 float *or = UArray_floatPointerAt_(mixBuffer
, index
+1);
471 for (i
= 0; i
< List_size(sounds
); i
++)
473 IoSound
*ioSound
= List_at_(sounds
, i
);
474 Sound
*sound
= IoSound_rawSound(ioSound
);
476 char done
= Sound_nextFloat(sound
, &left
, &right
);
478 if (done
&& !Sound_isLooping(sound
))
480 List_append_(soundsToRemove
, ioSound
);
488 ((!e
->ioTriggerSound
) ||
489 ((e
->ioTriggerSound
== ioSound
) &&
490 (e
->sample
== Sound_position(sound
))))
493 List_append_(DATA(self
)->activeEvents
, List_pop(DATA(self
)->events
));
494 e
= List_top(DATA(self
)->events
);
498 (*ol
) *= DATA(self
)->scale
;
499 (*or) *= DATA(self
)->scale
;
501 if (List_size(activeEvents
)) IoAudioMixer_processActiveEvents(self
);
502 if (List_size(soundsToRemove
)) IoAudioMixer_processSoundRemovals(self
);
505 /* adjust pitch and tempo */
507 //double t1 = ((double)clock())/((double)CLOCKS_PER_SEC);
509 int receivedSamples
= 1;
511 SoundTouch_putSamples(DATA(self
)->soundTouch
, (float *)UArray_bytes(mixBuffer
), samplesPerBuffer
);
512 //printf("put %i\n", samplesPerBuffer);
513 //while (receivedSamples)
515 UArray_setSize_(DATA(self
)->buffer
, 10000*8);
516 receivedSamples
= SoundTouch_receiveSamples(DATA(self
)->soundTouch
,
517 (float *)UArray_bytes(DATA(self
)->buffer
),
518 UArray_size(DATA(self
)->buffer
) / (sizeof(float) * 2));
519 UArray_setSize_(DATA(self
)->buffer
, receivedSamples
* (sizeof(float) * 2));
521 //printf("received %i\n", receivedSamples);
524 if (receivedSamples
< 5000)
527 printf("non-blocking write\n");
530 IoMessage_locals_performOn_(DATA(self
)->nonBlockingWriteMessage
,
531 self
, DATA(self
)->ioAudioDevice
);
535 IoMessage_locals_performOn_(DATA(self
)->writeMessage
,
536 self
, DATA(self
)->ioAudioDevice
);
540 t2
= ((double)clock())/((double)CLOCKS_PER_SEC
);
541 printf("tempo: %1.1f %i -> %i in %0.2f sec\n",
550 return receivedSamples
;
552 /* need to change this to be dynamic, so we can easily record the output */
553 /*IoAudioDevice_justWrite(DATA(self)->ioAudioDevice, locals, m, buffer);*/
554 return UArray_size(DATA(self
)->buffer
) / 8;
557 IoObject
*IoAudioMixer_setTempo(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
559 DATA(self
)->tempo
= IoMessage_locals_floatArgAt_(m
, locals
, 0);
560 SoundTouch_setTempo(DATA(self
)->soundTouch
, DATA(self
)->tempo
);
561 printf("IoAudioMixer_setTempo(%f)\n", DATA(self
)->tempo
);
562 IoAudioMixer_updateBufferSize(self
);
566 IoObject
*IoAudioMixer_setSampleRate(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
568 DATA(self
)->sampleRate
= IoMessage_locals_intArgAt_(m
, locals
, 0);
569 SoundTouch_setSampleRate(DATA(self
)->soundTouch
, (unsigned int)DATA(self
)->sampleRate
);
570 printf("IoAudioMixer_setSampleRate(%i)\n", DATA(self
)->sampleRate
);
571 IoAudioMixer_updateBufferSize(self
);
575 IoObject
*IoAudioMixer_setPitchSemiTones(IoAudioMixer
*self
, IoObject
*locals
, IoMessage
*m
)
577 DATA(self
)->pitch
= IoMessage_locals_floatArgAt_(m
, locals
, 0);
578 SoundTouch_setPitchSemiTones(DATA(self
)->soundTouch
, DATA(self
)->pitch
);
579 printf("IoAudioMixer_setPitchSemiTones(%f)\n", DATA(self
)->pitch
);
580 IoAudioMixer_updateBufferSize(self
);