*** empty log message ***
[chuck-blob.git] / v1 / digiio_rtaudio.cpp
blob20c6119e473cf006911d522f9cff972e9a190ee5
1 /*----------------------------------------------------------------------------
2 ChucK Concurrent, On-the-fly Audio Programming Language
3 Compiler and Virtual Machine
5 Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
6 http://chuck.cs.princeton.edu/
7 http://soundlab.cs.princeton.edu/
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 U.S.A.
23 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
26 // file: digiio_rtaudio.cpp
27 // desc: digitalio over rtaudio (from Gary Scavone)
29 // author: Ge Wang (gewang@cs.princeton.edu)
30 // Perry R. Cook (prc@cs.princeton.edu)
31 //-----------------------------------------------------------------------------
32 #include "digiio_rtaudio.h"
33 #include "chuck_vm.h"
34 #include "chuck_errmsg.h"
35 #include "rtaudio.h"
36 #if defined(__WINDOWS_DS__) && !defined(__WINDOWS_PTHREAD__)
37 #include <windows.h>
38 #else
39 #include <unistd.h>
40 #endif
45 // static
46 BOOL__ Digitalio::m_init = FALSE;
47 DWORD__ Digitalio::m_start = 0;
48 DWORD__ Digitalio::m_tick_count = 0;
49 DWORD__ Digitalio::m_num_channels_out = NUM_CHANNELS_DEFAULT;
50 DWORD__ Digitalio::m_num_channels_in = NUM_CHANNELS_DEFAULT;
51 DWORD__ Digitalio::m_sampling_rate = SAMPLING_RATE_DEFAULT;
52 DWORD__ Digitalio::m_bps = BITS_PER_SAMPLE_DEFAULT;
53 DWORD__ Digitalio::m_buffer_size = BUFFER_SIZE_DEFAULT;
54 DWORD__ Digitalio::m_num_buffers = NUM_BUFFERS_DEFAULT;
55 RtAudio * Digitalio::m_rtaudio = NULL;
56 SAMPLE * Digitalio::m_buffer_out = NULL;
57 SAMPLE * Digitalio::m_buffer_in = NULL;
58 SAMPLE ** Digitalio::m_write_ptr = NULL;
59 SAMPLE ** Digitalio::m_read_ptr = NULL;
60 SAMPLE * Digitalio::m_extern_in = NULL;
61 SAMPLE * Digitalio::m_extern_out = NULL;
62 BOOL__ Digitalio::m_out_ready = FALSE;
63 BOOL__ Digitalio::m_in_ready = FALSE;
64 BOOL__ Digitalio::m_use_cb = USE_CB_DEFAULT;
65 DWORD__ Digitalio::m_go = 0;
66 DWORD__ Digitalio::m_dac_n = 0;
67 DWORD__ Digitalio::m_adc_n = 0;
68 DWORD__ Digitalio::m_end = 0;
73 //-----------------------------------------------------------------------------
74 // name: initialize()
75 // desc: ...
76 //-----------------------------------------------------------------------------
77 BOOL__ Digitalio::initialize( DWORD__ num_channels, DWORD__ sampling_rate,
78 DWORD__ bps, DWORD__ buffer_size,
79 DWORD__ num_buffers )
81 if( m_init )
82 return FALSE;
84 m_num_channels_out = num_channels;
85 m_num_channels_in = num_channels;
86 m_sampling_rate = sampling_rate;
87 m_bps = bps;
88 m_buffer_size = buffer_size;
89 m_num_buffers = num_buffers;
90 m_start = 0;
91 m_tick_count = 0;
92 m_go = 0;
93 m_end = 0;
95 // allocate RtAudio
96 try { m_rtaudio = new RtAudio( ); }
97 catch( RtError err )
99 // problem finding audio devices, most likely
100 EM_error2( 0, "%s", err.getMessageString() );
101 return m_init = FALSE;
104 // open device
105 try {
106 m_rtaudio->openStream(
107 m_dac_n, m_num_channels_out, m_adc_n, m_num_channels_in,
108 RTAUDIO_FLOAT32, sampling_rate,
109 (int *)&m_buffer_size, num_buffers );
110 if( m_use_cb )
111 m_rtaudio->setStreamCallback( &cb, NULL );
112 } catch( RtError err ) {
113 try {
114 m_buffer_size = buffer_size;
115 // try output only
116 m_rtaudio->openStream(
117 m_dac_n, m_num_channels_out, 0, 0,
118 RTAUDIO_FLOAT32, sampling_rate,
119 (int *)&m_buffer_size, num_buffers );
120 if( m_use_cb )
121 m_rtaudio->setStreamCallback( &cb, NULL );
122 } catch( RtError err ) {
123 EM_error2( 0, "%s", err.getMessageString() );
124 SAFE_DELETE( m_rtaudio );
125 return m_init = FALSE;
129 if( m_use_cb )
131 m_buffer_in = new SAMPLE[m_buffer_size * num_channels];
132 m_buffer_out = new SAMPLE[m_buffer_size * num_channels];
133 memset( m_buffer_in, 0, m_buffer_size * sizeof(SAMPLE) * num_channels );
134 memset( m_buffer_out, 0, m_buffer_size * sizeof(SAMPLE) * num_channels );
135 m_read_ptr = NULL;
136 m_write_ptr = NULL;
139 m_in_ready = FALSE;
140 m_out_ready = FALSE;
142 return m_init = TRUE;
148 //-----------------------------------------------------------------------------
149 // name: cb()
150 // desc: ...
151 //-----------------------------------------------------------------------------
152 int Digitalio::cb( char * buffer, int buffer_size, void * user_data )
154 DWORD__ len = buffer_size * sizeof(SAMPLE) * m_num_channels_out;
155 DWORD__ n = 6;
156 DWORD__ start = 50;
158 // copy input to local buffer
159 if( m_num_channels_in )
161 memcpy( m_buffer_in, buffer, len );
162 // copy to extern
163 if( m_extern_in ) memcpy( m_extern_in, buffer, len );
165 // flag ready
166 m_in_ready = TRUE;
167 // out is ready early
168 if( m_go < start && m_go > 1 && m_out_ready ) m_go = start;
169 // copy output into local buffer
170 if( m_go >= start )
172 while( !m_out_ready && n-- ) usleep( 250 );
173 // copy local buffer to be rendered
174 if( m_out_ready && !m_end ) memcpy( buffer, m_buffer_out, len );
175 // set all elements of local buffer to silence
176 else memset( buffer, 0, len);
178 else // initial condition
180 //#ifndef __WINDOWS_DS__
181 if( !m_go && Chuck_VM::our_priority != 0x7fffffff )
182 Chuck_VM::set_priority( Chuck_VM::our_priority, NULL );
183 //#endif
184 memset( buffer, 0, len );
185 m_go++;
186 return 0;
189 // 2nd buffer
190 if( m_go == start )
192 n = 8; while( !m_out_ready && n-- ) usleep( 250 );
193 len /= sizeof(SAMPLE); DWORD__ i = 0;
194 SAMPLE * s = (SAMPLE *)buffer;
195 while( i < len ) *s++ *= (SAMPLE)i++/len;
196 m_go++;
199 // copy to extern
200 if( m_extern_out ) memcpy( m_extern_out, buffer, len );
202 // set pointer to the beginning - if not ready, then too late anyway
203 //*m_write_ptr = (SAMPLE *)m_buffer_out;
204 //*m_read_ptr = (SAMPLE *)m_buffer_in;
205 m_out_ready = FALSE;
207 return 0;
213 //-----------------------------------------------------------------------------
214 // name: start()
215 // desc: ...
216 //-----------------------------------------------------------------------------
217 BOOL__ Digitalio::start( )
219 try{ if( !m_start )
220 m_rtaudio->startStream();
221 m_start = TRUE;
222 } catch( RtError err ){ return FALSE; }
224 return m_start;
230 //-----------------------------------------------------------------------------
231 // name: stop()
232 // desc: ...
233 //-----------------------------------------------------------------------------
234 BOOL__ Digitalio::stop( )
236 try{ if( m_start )
237 m_rtaudio->stopStream();
238 m_start = FALSE;
239 } catch( RtError err ){ return FALSE; }
241 return !m_start;
247 //-----------------------------------------------------------------------------
248 // name: tick()
249 // desc: ...
250 //-----------------------------------------------------------------------------
251 BOOL__ Digitalio::tick( )
255 if( ++m_tick_count >= m_start )
257 m_rtaudio->tickStream();
258 m_tick_count = 0;
259 m_out_ready = TRUE;
260 m_in_ready = TRUE;
263 return TRUE;
264 } catch( RtError err ){ return FALSE; }
270 //-----------------------------------------------------------------------------
271 // name: shutdown()
272 // desc: ...
273 //-----------------------------------------------------------------------------
274 void Digitalio::shutdown()
276 if( !m_init ) return;
277 if( m_start ) m_rtaudio->stopStream();
279 m_rtaudio->closeStream();
280 SAFE_DELETE( m_rtaudio );
281 m_init = FALSE;
282 m_start = FALSE;
288 //-----------------------------------------------------------------------------
289 // name: DigitalOut()
290 // desc: ...
291 //-----------------------------------------------------------------------------
292 DigitalOut::DigitalOut()
294 m_data_ptr_out = NULL;
295 m_data_max_out = NULL;
301 //-----------------------------------------------------------------------------
302 // name: ~DigitalOut()
303 // desc: ...
304 //-----------------------------------------------------------------------------
305 DigitalOut::~DigitalOut()
307 this->cleanup();
313 //-----------------------------------------------------------------------------
314 // name: initialize()
315 // desc: initialize audio out
316 //-----------------------------------------------------------------------------
317 BOOL__ DigitalOut::initialize( )
319 // set pointer to beginning of local buffer
320 m_data_ptr_out = Digitalio::m_use_cb ? Digitalio::m_buffer_out
321 : (SAMPLE *)Digitalio::audio()->getStreamBuffer();
322 // calculate the end of the buffer
323 m_data_max_out = m_data_ptr_out +
324 Digitalio::buffer_size() * Digitalio::num_channels_out();
325 // set the writer pointer to our write pointer
326 Digitalio::m_write_ptr = &m_data_ptr_out;
328 return TRUE;
334 //-----------------------------------------------------------------------------
335 // name: start()
336 // desc: render
337 //-----------------------------------------------------------------------------
338 BOOL__ DigitalOut::start()
340 // start stream
341 return ( Digitalio::start() != 0 );
347 //-----------------------------------------------------------------------------
348 // name: stop()
349 // desc: render
350 //-----------------------------------------------------------------------------
351 BOOL__ DigitalOut::stop()
353 // well
354 Digitalio::stop();
356 return TRUE;
362 //-----------------------------------------------------------------------------
363 // name: cleanup()
364 // desc: ...
365 //-----------------------------------------------------------------------------
366 void DigitalOut::cleanup()
373 //-----------------------------------------------------------------------------
374 // name: tick_out()
375 // desc: 1 channel
376 //-----------------------------------------------------------------------------
377 BOOL__ DigitalOut::tick_out( SAMPLE sample )
379 if( !prepare_tick_out() )
380 return FALSE;
382 *m_data_ptr_out++ = sample;
384 return TRUE;
390 //-----------------------------------------------------------------------------
391 // name: tick_out()
392 // desc: 2 channel
393 //-----------------------------------------------------------------------------
394 BOOL__ DigitalOut::tick_out( SAMPLE sample_l, SAMPLE sample_r )
396 if( !prepare_tick_out() )
397 return FALSE;
399 *m_data_ptr_out++ = sample_l;
400 *m_data_ptr_out++ = sample_r;
402 return TRUE;
408 //-----------------------------------------------------------------------------
409 // name: tick_out()
410 // desc: all channels
411 //-----------------------------------------------------------------------------
412 BOOL__ DigitalOut::tick_out( const SAMPLE * samples, DWORD__ n )
414 if( !prepare_tick_out() )
415 return FALSE;
417 if( !n ) n = Digitalio::m_num_channels_out;
418 while( n-- )
419 *m_data_ptr_out++ = *samples++;
421 return TRUE;
427 //-----------------------------------------------------------------------------
428 // name: prepare_tick_out()
429 // desc: data ptr ok
430 //-----------------------------------------------------------------------------
431 inline BOOL__ DigitalOut::prepare_tick_out()
433 if( m_data_ptr_out >= m_data_max_out )
435 this->render();
438 return TRUE;
444 //-----------------------------------------------------------------------------
445 // name: render()
446 // desc: the render
447 //-----------------------------------------------------------------------------
448 DWORD__ DigitalOut::render()
450 //if( !Digitalio::m_use_cb && !Digitalio::tick() ) return FALSE;
452 // synchronize
453 Digitalio::m_out_ready = TRUE;
454 // synchronize
455 while( Digitalio::m_out_ready )
456 usleep( 250 );
457 // set pointer to the beginning - if not ready, then too late anyway
458 *Digitalio::m_write_ptr = (SAMPLE *)Digitalio::m_buffer_out;
460 return TRUE;
466 //-----------------------------------------------------------------------------
467 // name: DigitalIn()
468 // desc: ...
469 //-----------------------------------------------------------------------------
470 DigitalIn::DigitalIn()
472 m_data_ptr_in = NULL;
473 m_data_max_in = NULL;
479 //-----------------------------------------------------------------------------
480 // name: ~DigitalIn()
481 // desc: ...
482 //-----------------------------------------------------------------------------
483 DigitalIn::~DigitalIn()
485 this->cleanup();
491 //-----------------------------------------------------------------------------
492 // name: initialize()
493 // desc: initialize audio in
494 //-----------------------------------------------------------------------------
495 BOOL__ DigitalIn::initialize( )
497 m_data = new SAMPLE[Digitalio::buffer_size() * Digitalio::num_channels_in()];
498 // set the buffer to the beginning of the local buffer
499 m_data_ptr_in = Digitalio::m_use_cb ? m_data
500 : (SAMPLE *)Digitalio::audio()->getStreamBuffer();
501 // calculate past buffer
502 m_data_max_in = m_data_ptr_in +
503 Digitalio::buffer_size() * Digitalio::num_channels_in();
504 // set the read pointer to the local pointer
505 Digitalio::m_read_ptr = &m_data_ptr_in;
507 return TRUE;
513 //-----------------------------------------------------------------------------
514 // name: start()
515 // desc: ...
516 //-----------------------------------------------------------------------------
517 BOOL__ DigitalIn::start()
519 return ( Digitalio::start() != 0 );
525 //-----------------------------------------------------------------------------
526 // name: capture_stop()
527 // desc: ...
528 //-----------------------------------------------------------------------------
529 BOOL__ DigitalIn::stop()
531 Digitalio::stop();
532 return TRUE;
538 //-----------------------------------------------------------------------------
539 // name: cleanup()
540 // desc: ...
541 //-----------------------------------------------------------------------------
542 void DigitalIn::cleanup()
549 //-----------------------------------------------------------------------------
550 // name: tick_in()
551 // desc: ...
552 //-----------------------------------------------------------------------------
553 BOOL__ DigitalIn::tick_in( SAMPLE * s )
555 if( !prepare_tick_in() )
556 return 0;
558 *s = *m_data_ptr_in++;
560 return TRUE;
566 //-----------------------------------------------------------------------------
567 // name: tick_in()
568 // desc: ...
569 //-----------------------------------------------------------------------------
570 BOOL__ DigitalIn::tick_in( SAMPLE * l, SAMPLE * r )
572 if( !prepare_tick_in() )
573 return FALSE;
575 *l = *m_data_ptr_in++;
576 *r = *m_data_ptr_in++;
578 return TRUE;
584 //-----------------------------------------------------------------------------
585 // name: tick_in()
586 // desc: ...
587 //-----------------------------------------------------------------------------
588 BOOL__ DigitalIn::tick_in( SAMPLE * sample, DWORD__ n )
590 if( !prepare_tick_in() )
591 return FALSE;
593 if( !n ) n = Digitalio::m_num_channels_in;
594 while( n-- )
595 *sample++ = *m_data_ptr_in++;
597 return TRUE;
603 //-----------------------------------------------------------------------------
604 // name: prepare_tick_in()
605 // desc: data ptr ok
606 //-----------------------------------------------------------------------------
607 inline BOOL__ DigitalIn::prepare_tick_in()
609 if( m_data_ptr_in >= m_data_max_in )
611 this->capture();
614 return TRUE;
620 //-----------------------------------------------------------------------------
621 // name: cb_capture()
622 // desc: ...
623 //-----------------------------------------------------------------------------
624 DWORD__ DigitalIn::capture( )
626 // if( !Digitalio::m_use_cb && !Digitalio::tick() ) return FALSE;
628 t_CKUINT n = 4;
629 while( !Digitalio::m_in_ready && n-- )
630 usleep( 250 );
632 // copy data
633 memcpy( m_data, Digitalio::m_buffer_in, Digitalio::buffer_size() *
634 Digitalio::num_channels_in() * sizeof(SAMPLE) );
635 Digitalio::m_in_ready = FALSE;
636 // set pointer to the beginning - if not ready, then too late anyway
637 *Digitalio::m_read_ptr = (SAMPLE *)m_data;
639 return TRUE;
645 //-----------------------------------------------------------------------------
646 // name: AudioBufferX()
647 // desc: ...
648 //-----------------------------------------------------------------------------
649 AudioBufferX::AudioBufferX( DWORD__ size )
651 if( size )
652 this->initialize( size );
653 else
655 m_size = size;
656 m_data = m_ptr_curr = m_ptr_end = NULL;
663 //-----------------------------------------------------------------------------
664 // name: initialize()
665 // desc: ...
666 //-----------------------------------------------------------------------------
667 BOOL__ AudioBufferX::initialize( DWORD__ size )
669 m_size = size;
670 m_data = (SAMPLE *)malloc( size * sizeof(SAMPLE) );
672 if( !m_data )
673 return FALSE;
675 // clear the memory
676 memset( m_data, 0, size * sizeof(SAMPLE) );
678 // set the pointers
679 m_ptr_curr = m_data;
680 m_ptr_end = m_data + size;
682 return TRUE;
688 //-----------------------------------------------------------------------------
689 // name: cleanup()
690 // desc: ...
691 //-----------------------------------------------------------------------------
692 void AudioBufferX::cleanup()
694 if( m_data )
696 free( m_data );
697 m_data = NULL;
700 m_size = 0;
701 m_ptr_curr = m_ptr_end = NULL;
707 //-----------------------------------------------------------------------------
708 // name: size()
709 // desc: ...
710 //-----------------------------------------------------------------------------
711 DWORD__ AudioBufferX::size()
713 return m_size;
719 //-----------------------------------------------------------------------------
720 // name: data()
721 // desc: ...
722 //-----------------------------------------------------------------------------
723 SAMPLE * AudioBufferX::data()
725 return m_data;
731 //-----------------------------------------------------------------------------
732 // name: AudioBufferIn()
733 // desc: ...
734 //-----------------------------------------------------------------------------
735 AudioBufferIn::AudioBufferIn( DWORD__ size )
736 : AudioBufferX( size )
742 //-----------------------------------------------------------------------------
743 // name: ~AudioBufferIn()
744 // desc: ...
745 //-----------------------------------------------------------------------------
746 AudioBufferIn::~AudioBufferIn()
748 this->cleanup();
754 //-----------------------------------------------------------------------------
755 // name: reset()
756 // desc: ...
757 //-----------------------------------------------------------------------------
758 BOOL__ AudioBufferIn::reset()
760 m_ptr_curr = m_data;
762 return TickIn::reset();
768 //-----------------------------------------------------------------------------
769 // name: tick_in()
770 // desc: ...
771 //-----------------------------------------------------------------------------
772 BOOL__ AudioBufferIn::tick_in( SAMPLE * s )
774 if( !m_data )
775 return FALSE;
777 *s = *m_ptr_curr++;
779 return TRUE;
785 //-----------------------------------------------------------------------------
786 // name: tick_in()
787 // desc: ...
788 //-----------------------------------------------------------------------------
789 BOOL__ AudioBufferIn::tick_in( SAMPLE * l, SAMPLE * r )
791 if( !m_data || m_ptr_curr + 2 >= m_ptr_end )
792 return FALSE;
794 *l = *m_ptr_curr++;
795 *r = *m_ptr_curr++;
797 return TRUE;
803 //-----------------------------------------------------------------------------
804 // name: tick_in()
805 // desc: ...
806 //-----------------------------------------------------------------------------
807 BOOL__ AudioBufferIn::tick_in( SAMPLE * in, DWORD__ n )
809 if( !m_data || m_ptr_curr + n >= m_ptr_end )
810 return FALSE;
812 while( n-- )
813 *in++ = *m_ptr_curr++;
815 return TRUE;
821 //-----------------------------------------------------------------------------
822 // name: AudioBufferOut()
823 // desc: ...
824 //-----------------------------------------------------------------------------
825 AudioBufferOut::AudioBufferOut( DWORD__ size )
826 : AudioBufferX( size )
832 //-----------------------------------------------------------------------------
833 // name: ~AudioBufferOut()
834 // desc: ...
835 //-----------------------------------------------------------------------------
836 AudioBufferOut::~AudioBufferOut()
838 this->cleanup();
844 //-----------------------------------------------------------------------------
845 // name: reset()
846 // desc: ...
847 //-----------------------------------------------------------------------------
848 BOOL__ AudioBufferOut::reset()
850 m_ptr_curr = m_data;
852 return TickOut::reset();
858 //-----------------------------------------------------------------------------
859 // name: tick_out()
860 // desc: ...
861 //-----------------------------------------------------------------------------
862 BOOL__ AudioBufferOut::tick_out( SAMPLE s )
864 if( !m_data )
865 return FALSE;
867 *m_ptr_curr++ = s;
869 return TRUE;
875 //-----------------------------------------------------------------------------
876 // name: tick_out()
877 // desc: ...
878 //-----------------------------------------------------------------------------
879 BOOL__ AudioBufferOut::tick_out( SAMPLE l, SAMPLE r )
881 if( !m_data || m_ptr_curr + 2 >= m_ptr_end )
882 return FALSE;
884 *m_ptr_curr++ = l;
885 *m_ptr_curr++ = r;
887 return TRUE;
893 //-----------------------------------------------------------------------------
894 // name: tick_out()
895 // desc: ...
896 //-----------------------------------------------------------------------------
897 BOOL__ AudioBufferOut::tick_out( const SAMPLE * out, DWORD__ n )
899 if( !m_data || m_ptr_curr + n >= m_ptr_end )
900 return FALSE;
902 while( n-- )
903 *m_ptr_curr++ = *out++;
905 return TRUE;