*** empty log message ***
[chuck-blob.git] / v2 / digiio_rtaudio.cpp
blob372e6bd66a9b14d770575e71cbb5a21d2c3f8d0d
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 "chuck_globals.h"
36 #ifndef __DISABLE_RTAUDIO__
37 #include "rtaudio.h"
38 #endif // __DISABLE_RTAUDIO__
39 #if defined(__CHIP_MODE__)
40 #include "../small.h">
41 #endif // __CHIP_MODE__
42 #ifndef __DISABLE_MIDI__
43 #include "rtmidi.h"
44 #endif // __DISABLE_MIDI__
45 // #include <signal.h>
46 #if (defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__)) && !defined(__WINDOWS_PTHREAD__)
47 #include <windows.h>
48 #include <sys/timeb.h>
49 #else
50 #include <unistd.h>
51 #include <sys/time.h>
52 #endif
54 // extern "C" void signal_int( int );
56 // static
57 BOOL__ Digitalio::m_init = FALSE;
58 DWORD__ Digitalio::m_start = 0;
59 DWORD__ Digitalio::m_tick_count = 0;
60 DWORD__ Digitalio::m_num_channels_out = NUM_CHANNELS_DEFAULT;
61 DWORD__ Digitalio::m_num_channels_in = NUM_CHANNELS_DEFAULT;
62 DWORD__ Digitalio::m_sampling_rate = SAMPLING_RATE_DEFAULT;
63 DWORD__ Digitalio::m_bps = BITS_PER_SAMPLE_DEFAULT;
64 DWORD__ Digitalio::m_buffer_size = BUFFER_SIZE_DEFAULT;
65 DWORD__ Digitalio::m_num_buffers = NUM_BUFFERS_DEFAULT;
66 RtAudio * Digitalio::m_rtaudio = NULL;
67 SAMPLE * Digitalio::m_buffer_out = NULL;
68 SAMPLE * Digitalio::m_buffer_in = NULL;
69 SAMPLE ** Digitalio::m_write_ptr = NULL;
70 SAMPLE ** Digitalio::m_read_ptr = NULL;
71 SAMPLE * Digitalio::m_extern_in = NULL;
72 SAMPLE * Digitalio::m_extern_out = NULL;
73 BOOL__ Digitalio::m_out_ready = FALSE;
74 BOOL__ Digitalio::m_in_ready = FALSE;
75 BOOL__ Digitalio::m_use_cb = USE_CB_DEFAULT;
76 DWORD__ Digitalio::m_go = 0;
77 DWORD__ Digitalio::m_dac_n = 0;
78 DWORD__ Digitalio::m_adc_n = 0;
79 DWORD__ Digitalio::m_end = 0;
80 DWORD__ Digitalio::m_block = TRUE;
81 DWORD__ Digitalio::m_xrun = 0;
84 // sample
85 #if defined(CK_S_DOUBLE)
86 #define CK_RTAUDIO_FORMAT RTAUDIO_FLOAT64
87 #else
88 #define CK_RTAUDIO_FORMAT RTAUDIO_FLOAT32
89 #endif
94 #ifndef __DISABLE_RTAUDIO__
95 //-----------------------------------------------------------------------------
96 // name: print()
97 // desc: ...
98 //-----------------------------------------------------------------------------
99 void print( const RtAudioDeviceInfo & info )
101 EM_error2b( 0, "device name = \"%s\"", info.name.c_str() );
102 if (info.probed == false)
103 EM_error2b( 0, "probe [failed] ..." );
104 else
106 EM_error2b( 0, "probe [success] ..." );
107 EM_error2b( 0, "# output channels = %d", info.outputChannels );
108 EM_error2b( 0, "# input channels = %d", info.inputChannels );
109 EM_error2b( 0, "# duplex Channels = %d", info.duplexChannels );
110 if( info.isDefault ) EM_error2b( 0, "default device = YES" );
111 else EM_error2b( 0, "default device = NO" );
112 if( info.nativeFormats == 0 ) EM_error2b( 0, "no natively supported data formats(?)!" );
113 else
115 EM_error2b( 0, "natively supported data formats:" );
116 if( info.nativeFormats & RTAUDIO_SINT8 ) EM_error2b( 0, " 8-bit int" );
117 if( info.nativeFormats & RTAUDIO_SINT16 ) EM_error2b( 0, " 16-bit int" );
118 if( info.nativeFormats & RTAUDIO_SINT24 ) EM_error2b( 0, " 24-bit int" );
119 if( info.nativeFormats & RTAUDIO_SINT32 ) EM_error2b( 0, " 32-bit int" );
120 if( info.nativeFormats & RTAUDIO_FLOAT32 ) EM_error2b( 0, " 32-bit float" );
121 if( info.nativeFormats & RTAUDIO_FLOAT64 ) EM_error2b( 0, " 64-bit float" );
123 if ( info.sampleRates.size() < 1 ) EM_error2b( 0,"no supported sample rates found!" );
124 else
126 EM_error2b( 0, "supported sample rates:" );
127 for( unsigned int j = 0; j < info.sampleRates.size(); j++ )
128 EM_error2b( 0, " %d Hz", info.sampleRates[j] );
132 #endif // __DISABLE_RTAUDIO__
137 //-----------------------------------------------------------------------------
138 // name: probe()
139 // desc: ...
140 //-----------------------------------------------------------------------------
141 void Digitalio::probe()
143 #ifndef __DISABLE_RTAUDIO__
144 RtAudio * rta = NULL;
145 RtAudioDeviceInfo info;
147 // allocate RtAudio
148 try { rta = new RtAudio( ); }
149 catch( RtError err )
151 // problem finding audio devices, most likely
152 EM_error2b( 0, "%s", err.getMessageString() );
153 return;
156 // get count
157 int devices = rta->getDeviceCount();
158 EM_error2b( 0, "found %d device(s) ...", devices );
159 // EM_error2( 0, "--------------------------" );
161 // loop
162 for( int i = 1; i <= devices; i++ )
164 try { info = rta->getDeviceInfo(i); }
165 catch( RtError & error )
167 error.printMessage();
168 break;
171 // print
172 EM_error2b( 0, "------( chuck -- dac%d )---------------", i );
173 print( info );
174 // skip
175 if( i < devices ) EM_error2( 0, "" );
178 delete rta;
179 #endif // __DISABLE_RTAUDIO__
181 return;
187 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
188 //-----------------------------------------------------------------------------
189 // name: set_priority()
190 // desc: ...
191 //-----------------------------------------------------------------------------
192 static t_CKBOOL set_priority( CHUCK_THREAD tid, t_CKINT priority )
194 struct sched_param param;
195 int policy;
197 // log
198 EM_log( CK_LOG_FINE, "setting thread priority to: %ld...", priority );
200 // get for thread
201 if( pthread_getschedparam( tid, &policy, &param) )
202 return FALSE;
204 // priority
205 param.sched_priority = priority;
206 // policy
207 policy = SCHED_RR;
208 // set for thread
209 if( pthread_setschedparam( tid, policy, &param ) )
210 return FALSE;
212 return TRUE;
214 #else
215 //-----------------------------------------------------------------------------
216 // name: set_priority()
217 // desc: ...
218 //-----------------------------------------------------------------------------
219 static t_CKBOOL set_priority( CHUCK_THREAD tid, t_CKINT priority )
221 // if priority is 0 then done
222 if( !priority ) return TRUE;
224 // log
225 EM_log( CK_LOG_FINE, "setting thread priority to: %ld...", priority );
227 // set the priority the thread
228 if( !SetThreadPriority( tid, priority ) )
229 return FALSE;
231 return TRUE;
233 #endif
236 //-----------------------------------------------------------------------------
237 // name: get_current_time()
238 // desc: ...
239 //-----------------------------------------------------------------------------
240 static t_CKFLOAT get_current_time( t_CKBOOL fresh = TRUE )
242 #ifdef __PLATFORM_WIN32__
243 struct _timeb t;
244 _ftime(&t);
245 return t.time + t.millitm/1000.0;
246 #else
247 static struct timeval t;
248 if( fresh ) gettimeofday(&t,NULL);
249 return t.tv_sec + (t_CKFLOAT)t.tv_usec/1000000;
250 #endif
252 return 0;
256 // watch dog globals
257 static CHUCK_THREAD g_tid_synthesis = 0;
258 static XThread * g_watchdog_thread = NULL;
259 static t_CKBOOL g_watchdog_state = FALSE;
260 static t_CKFLOAT g_watchdog_time = 0;
263 //-----------------------------------------------------------------------------
264 // name: watch_dog()
265 // desc: ...
266 //-----------------------------------------------------------------------------
267 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
268 static void * watch_dog( void * )
269 #else
270 static unsigned int __stdcall watch_dog( void * )
271 #endif
273 t_CKFLOAT time;
275 // boost priority?
276 t_CKUINT priority = Chuck_VM::our_priority;
278 // log
279 EM_log( CK_LOG_SEVERE, "starting real-time watch dog processs..." );
280 // push log
281 EM_pushlog();
282 EM_log( CK_LOG_INFO, "watchdog timeout: %f::second", g_watchdog_timeout );
283 EM_log( CK_LOG_INFO, "watchdog thread priority: %d", priority );
284 EM_log( CK_LOG_INFO, "watchdog countermeasure priority: %d", g_watchdog_countermeasure_priority );
285 // pop log
286 EM_poplog();
288 // boost watchdog by same priority
289 if( Chuck_VM::our_priority != 0x7fffffff )
290 Chuck_VM::set_priority( priority, NULL );
292 // while going
293 while( g_do_watchdog )
295 // get
296 time = get_current_time( TRUE );
297 // fprintf( stderr, "last: %f now: %f\n", g_watchdog_time, time );
299 // resting
300 if( g_watchdog_state == FALSE )
302 // check xrun
303 // if( Digitalio::m_xrun > 100 )
304 if( time - g_watchdog_time > g_watchdog_timeout )
306 // log
307 EM_log( CK_LOG_SEVERE, "real-time watchdog counter-measure activating..." );
308 // lowering priority
309 if( g_tid_synthesis && Chuck_VM::our_priority != 0x7fffffff )
310 set_priority( g_tid_synthesis, g_watchdog_countermeasure_priority );
311 // set state
312 g_watchdog_state = TRUE;
315 else
317 // check xrun
318 // if( Digitalio::m_xrun == 0 )
319 if( time - g_watchdog_time < g_watchdog_timeout )
321 // log
322 EM_log( CK_LOG_SEVERE, "real-time watchdog resting..." );
323 // raise priority
324 if( g_tid_synthesis && Chuck_VM::our_priority != 0x7fffffff )
325 set_priority( g_tid_synthesis, Chuck_VM::our_priority );
326 // set state
327 g_watchdog_state = FALSE;
331 // advance time
332 usleep( 40000 );
335 // log
336 EM_log( CK_LOG_SEVERE, "stopping real-time watch dog process..." );
338 return 0;
344 //-----------------------------------------------------------------------------
345 // name: watchdog_start()
346 // desc: ...
347 //-----------------------------------------------------------------------------
348 BOOL__ Digitalio::watchdog_start()
350 // already
351 if( g_watchdog_thread )
352 return FALSE;
354 // flag
355 g_do_watchdog = TRUE;
356 // allocate it
357 g_watchdog_thread = new XThread;
358 // start it
359 g_watchdog_thread->start( watch_dog, NULL );
361 return TRUE;
366 //-----------------------------------------------------------------------------
367 // name: watchdog_stop()
368 // desc: ...
369 //-----------------------------------------------------------------------------
370 BOOL__ Digitalio::watchdog_stop()
372 // already
373 if( !g_watchdog_thread )
374 return FALSE;
376 // stop things
377 g_do_watchdog = FALSE;
378 // wait a bit
379 // usleep( 100000 )
380 SAFE_DELETE( g_watchdog_thread );
382 return TRUE;
388 //-----------------------------------------------------------------------------
389 // name: initialize()
390 // desc: ...
391 //-----------------------------------------------------------------------------
392 BOOL__ Digitalio::initialize( DWORD__ num_dac_channels,
393 DWORD__ num_adc_channels,
394 DWORD__ sampling_rate,
395 DWORD__ bps, DWORD__ buffer_size,
396 DWORD__ num_buffers, DWORD__ block,
397 Chuck_VM * vm_ref, BOOL__ rt_audio,
398 void * callback, void * data )
400 if( m_init )
401 return FALSE;
403 m_num_channels_out = num_dac_channels;
404 m_num_channels_in = num_adc_channels;
405 m_sampling_rate = sampling_rate;
406 m_bps = bps;
407 m_buffer_size = buffer_size;
408 m_num_buffers = num_buffers;
409 m_start = 0;
410 m_tick_count = 0;
411 m_go = 0;
412 m_end = 0;
413 m_block = block;
415 DWORD__ num_channels;
416 int bufsize = m_buffer_size;
418 // if rt_audio is false, then set block to FALSE to avoid deadlock
419 if( !rt_audio ) m_block = FALSE;
421 #ifndef __DISABLE_RTAUDIO__
422 // if real-time audio
423 if( rt_audio )
425 // allocate RtAudio
426 try { m_rtaudio = new RtAudio( ); }
427 catch( RtError err )
429 // problem finding audio devices, most likely
430 EM_error2( 0, "%s", err.getMessageString() );
431 return m_init = FALSE;
434 // log
435 EM_log( CK_LOG_FINE, "initializing RtAudio..." );
436 // push indent
437 EM_pushlog();
439 // open device
440 try {
441 // log
442 EM_log( CK_LOG_FINE, "trying %d input %d output...",
443 m_num_channels_in, m_num_channels_out );
444 // open RtAudio
445 m_rtaudio->openStream(
446 m_dac_n, m_num_channels_out, m_adc_n, m_num_channels_in,
447 CK_RTAUDIO_FORMAT, sampling_rate,
448 &bufsize, num_buffers );
449 // set callback
450 if( m_use_cb )
452 // log
453 EM_log( CK_LOG_INFO, "initializing callback..." );
454 if( !callback )
456 if( block ) m_rtaudio->setStreamCallback( &cb, vm_ref );
457 else m_rtaudio->setStreamCallback( &cb2, vm_ref );
459 else
461 m_rtaudio->setStreamCallback( (RtAudioCallback)callback, data );
464 } catch( RtError err ) {
465 // log
466 EM_log( CK_LOG_INFO, "exception caught: '%s'...", err.getMessageString() );
467 EM_log( CK_LOG_INFO, "trying %d input %d output...", 0, m_num_channels_out );
468 try {
469 bufsize = buffer_size;
470 // try output only
471 m_rtaudio->openStream(
472 m_dac_n, m_num_channels_out, 0, 0,
473 RTAUDIO_FLOAT32, sampling_rate,
474 &bufsize, num_buffers );
475 // set callback
476 if( m_use_cb )
478 // log
479 EM_log( CK_LOG_INFO, "initializing callback (again)..." );
480 if( !callback )
482 if( block ) m_rtaudio->setStreamCallback( &cb, vm_ref );
483 else m_rtaudio->setStreamCallback( &cb2, vm_ref );
485 else
487 m_rtaudio->setStreamCallback( (RtAudioCallback)callback, data );
490 } catch( RtError err ) {
491 EM_error2( 0, "%s", err.getMessageString() );
492 SAFE_DELETE( m_rtaudio );
493 return m_init = FALSE;
497 // check bufsize
498 if( bufsize != (int)m_buffer_size )
500 EM_log( CK_LOG_SEVERE, "new buffer size: %d -> %i", m_buffer_size, bufsize );
501 m_buffer_size = bufsize;
504 // pop indent
505 EM_poplog();
507 #endif // __DISABLE_RTAUDIO__
509 #if defined(__CHIP_MODE__)
510 if( !SMALL::init( sampling_rate, buffer_size, 2 ) )
512 EM_error2( 0, "%s", "(chuck)error: unable to initialize SMALL..." );
513 return m_init = FALSE;
515 #endif // __CHIP_MODE__
517 if( m_use_cb )
519 num_channels = num_dac_channels > num_adc_channels ?
520 num_dac_channels : num_adc_channels;
521 // log
522 EM_log( CK_LOG_SEVERE, "allocating buffers for %d x %d samples...",
523 m_buffer_size, num_channels );
524 // allocate buffers
525 m_buffer_in = new SAMPLE[m_buffer_size * num_channels];
526 m_buffer_out = new SAMPLE[m_buffer_size * num_channels];
527 memset( m_buffer_in, 0, m_buffer_size * sizeof(SAMPLE) * num_channels );
528 memset( m_buffer_out, 0, m_buffer_size * sizeof(SAMPLE) * num_channels );
529 m_read_ptr = NULL;
530 m_write_ptr = NULL;
533 m_in_ready = FALSE;
534 m_out_ready = FALSE;
536 return m_init = TRUE;
542 //-----------------------------------------------------------------------------
543 // name: cb()
544 // desc: ...
545 //-----------------------------------------------------------------------------
546 int Digitalio::cb( char * buffer, int buffer_size, void * user_data )
548 DWORD__ len = buffer_size * sizeof(SAMPLE) * m_num_channels_out;
549 DWORD__ n = 20;
550 DWORD__ start = 50;
552 // copy input to local buffer
553 if( m_num_channels_in )
555 memcpy( m_buffer_in, buffer, len );
556 // copy to extern
557 if( m_extern_in ) memcpy( m_extern_in, buffer, len );
559 // flag ready
560 m_in_ready = TRUE;
561 // out is ready early
562 if( m_go < start && m_go > 1 && m_out_ready ) m_go = start;
563 // copy output into local buffer
564 if( m_go >= start )
566 while( !m_out_ready && n-- ) usleep( 250 );
567 if( m_out_ready && g_do_watchdog )
568 g_watchdog_time = get_current_time( TRUE );
569 // copy local buffer to be rendered
570 if( m_out_ready && !m_end ) memcpy( buffer, m_buffer_out, len );
571 // set all elements of local buffer to silence
572 else memset( buffer, 0, len );
574 else // initial condition
576 // priority boost
577 if( !m_go && Chuck_VM::our_priority != 0x7fffffff )
578 Chuck_VM::set_priority( Chuck_VM::our_priority, NULL );
579 // catch SIGINT
580 // signal( SIGINT, signal_int );
582 // timestamp
583 if( g_do_watchdog ) g_watchdog_time = get_current_time( TRUE );
585 memset( buffer, 0, len );
586 m_go++;
587 return 0;
590 // 2nd buffer
591 if( m_go == start )
593 n = 8; while( !m_out_ready && n-- ) usleep( 250 );
594 len /= sizeof(SAMPLE); DWORD__ i = 0;
595 SAMPLE * s = (SAMPLE *)buffer;
596 while( i < len ) *s++ *= (SAMPLE)i++/len;
597 m_go++;
600 // copy to extern
601 if( m_extern_out ) memcpy( m_extern_out, buffer, len );
603 // set pointer to the beginning - if not ready, then too late anyway
604 //*m_write_ptr = (SAMPLE *)m_buffer_out;
605 //*m_read_ptr = (SAMPLE *)m_buffer_in;
606 m_out_ready = FALSE;
608 return 0;
614 //-----------------------------------------------------------------------------
615 // name: cb2()
616 // desc: ...
617 //-----------------------------------------------------------------------------
618 int Digitalio::cb2( char * buffer, int buffer_size, void * user_data )
620 DWORD__ len = buffer_size * sizeof(SAMPLE) * m_num_channels_out;
621 Chuck_VM * vm_ref = (Chuck_VM *)user_data;
623 // priority boost
624 if( !m_go && Chuck_VM::our_priority != 0x7fffffff )
626 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
627 g_tid_synthesis = pthread_self();
628 #else
629 // must duplicate for handle to be usable by other threads
630 g_tid_synthesis = NULL;
631 DuplicateHandle(
632 GetCurrentProcess(),
633 GetCurrentThread(),
634 GetCurrentProcess(),
635 &g_tid_synthesis,
637 FALSE,
638 DUPLICATE_SAME_ACCESS
641 // TODO: close the duplicate handle?
642 #endif
643 Chuck_VM::set_priority( Chuck_VM::our_priority, NULL );
644 memset( buffer, 0, len );
645 m_go = TRUE;
647 // start watchdog
648 if( g_do_watchdog )
650 // timestamp
651 g_watchdog_time = get_current_time( TRUE );
652 // start watchdog
653 watchdog_start();
656 // let it go the first time
657 return 0;
660 // copy input to local buffer
661 if( m_num_channels_in )
663 memcpy( m_buffer_in, buffer, len );
664 // copy to extern
665 if( m_extern_in ) memcpy( m_extern_in, buffer, len );
668 // check xrun
669 if( m_xrun < 6 )
671 // timestamp
672 if( g_do_watchdog ) g_watchdog_time = get_current_time( TRUE );
673 // get samples from output
674 vm_ref->run( buffer_size );
675 // ...
676 if( m_xrun ) m_xrun--;
678 else
680 // reset
681 m_xrun /= 2;
684 // copy local buffer to be rendered
685 if( !m_end ) memcpy( buffer, m_buffer_out, len );
686 // set all elements of local buffer to silence
687 else memset( buffer, 0, len );
689 // copy to extern
690 if( m_extern_out ) memcpy( m_extern_out, buffer, len );
693 return 0;
699 #ifdef __SMALL_MODE__
700 //-----------------------------------------------------------------------------
701 // name: small_cb()
702 // desc: ...
703 //-----------------------------------------------------------------------------
704 void small_cb( Float32 * buffer, UInt32 numFrames, void * userData )
706 Digitalio::cb2( (char *)buffer, numFrames, userData );
708 #endif __SMALL_MODE__
713 //-----------------------------------------------------------------------------
714 // name: start()
715 // desc: ...
716 //-----------------------------------------------------------------------------
717 BOOL__ Digitalio::start( )
719 #ifndef __DISABLE_RTAUDIO__
720 try{ if( !m_start )
721 m_rtaudio->startStream();
722 m_start = TRUE;
723 } catch( RtError err ){ return FALSE; }
724 #endif // __DISABLE_RTAUDIO__
726 #if defined(__CHIP_MODE__)
727 if( !m_start )
728 m_start = SMALL::start( small_cb, g_vm );
729 #endif // __CHIP_MODE__
731 return m_start;
737 //-----------------------------------------------------------------------------
738 // name: stop()
739 // desc: ...
740 //-----------------------------------------------------------------------------
741 BOOL__ Digitalio::stop( )
743 #ifndef __DISABLE_RTAUDIO__
744 try{ if( m_start )
745 m_rtaudio->stopStream();
746 m_start = FALSE;
747 } catch( RtError err ){ return FALSE; }
748 #endif // __DISABLE_RTAUDIO__
750 #if defined(__CHIP_MODE__)
751 if( m_start )
752 SMALL::stop();
753 m_start = FALSE;
754 #endif
756 return !m_start;
762 //-----------------------------------------------------------------------------
763 // name: tick()
764 // desc: ...
765 //-----------------------------------------------------------------------------
766 BOOL__ Digitalio::tick( )
768 #ifndef __DISABLE_RTAUDIO__
771 if( ++m_tick_count >= m_start )
773 m_rtaudio->tickStream();
774 m_tick_count = 0;
775 m_out_ready = TRUE;
776 m_in_ready = TRUE;
779 return TRUE;
780 } catch( RtError err ){ return FALSE; }
781 #endif // __DISABLE_RTAUDIO__
783 return FALSE;
789 //-----------------------------------------------------------------------------
790 // name: shutdown()
791 // desc: ...
792 //-----------------------------------------------------------------------------
793 void Digitalio::shutdown()
795 if( !m_init ) return;
797 #ifndef __DISABLE_RTAUDIO__
798 if( m_start )
800 if( m_use_cb ) m_rtaudio->cancelStreamCallback();
801 m_rtaudio->stopStream();
804 m_rtaudio->closeStream();
805 SAFE_DELETE( m_rtaudio );
806 #endif // __DISABLE_RTAUDIO__
808 m_init = FALSE;
809 m_start = FALSE;
811 // stop watchdog
812 watchdog_stop();
818 //-----------------------------------------------------------------------------
819 // name: DigitalOut()
820 // desc: ...
821 //-----------------------------------------------------------------------------
822 DigitalOut::DigitalOut()
824 m_data_ptr_out = NULL;
825 m_data_max_out = NULL;
831 //-----------------------------------------------------------------------------
832 // name: ~DigitalOut()
833 // desc: ...
834 //-----------------------------------------------------------------------------
835 DigitalOut::~DigitalOut()
837 this->cleanup();
843 //-----------------------------------------------------------------------------
844 // name: initialize()
845 // desc: initialize audio out
846 //-----------------------------------------------------------------------------
847 BOOL__ DigitalOut::initialize( )
849 #ifndef __DISABLE_RTAUDIO__
850 // set pointer to beginning of local buffer
851 m_data_ptr_out = Digitalio::m_use_cb ? Digitalio::m_buffer_out
852 : (SAMPLE *)Digitalio::audio()->getStreamBuffer();
853 #else
854 // set pointer
855 assert( Digitalio::m_use_cb );
856 m_data_ptr_out = Digitalio::m_buffer_out;
857 #endif // __DISABLE_RTAUDIO__
858 // calculate the end of the buffer
859 m_data_max_out = m_data_ptr_out +
860 Digitalio::buffer_size() * Digitalio::num_channels_out();
861 // set the writer pointer to our write pointer
862 Digitalio::m_write_ptr = &m_data_ptr_out;
864 return TRUE;
870 //-----------------------------------------------------------------------------
871 // name: start()
872 // desc: render
873 //-----------------------------------------------------------------------------
874 BOOL__ DigitalOut::start()
876 // start stream
877 return ( Digitalio::start() != 0 );
883 //-----------------------------------------------------------------------------
884 // name: stop()
885 // desc: render
886 //-----------------------------------------------------------------------------
887 BOOL__ DigitalOut::stop()
889 // well
890 Digitalio::stop();
892 return TRUE;
898 //-----------------------------------------------------------------------------
899 // name: cleanup()
900 // desc: ...
901 //-----------------------------------------------------------------------------
902 void DigitalOut::cleanup()
909 //-----------------------------------------------------------------------------
910 // name: tick_out()
911 // desc: 1 channel
912 //-----------------------------------------------------------------------------
913 BOOL__ DigitalOut::tick_out( SAMPLE sample )
915 if( !prepare_tick_out() )
916 return FALSE;
918 *m_data_ptr_out++ = sample;
920 return TRUE;
926 //-----------------------------------------------------------------------------
927 // name: tick_out()
928 // desc: 2 channel
929 //-----------------------------------------------------------------------------
930 BOOL__ DigitalOut::tick_out( SAMPLE sample_l, SAMPLE sample_r )
932 if( !prepare_tick_out() )
933 return FALSE;
935 *m_data_ptr_out++ = sample_l;
936 *m_data_ptr_out++ = sample_r;
938 return TRUE;
944 //-----------------------------------------------------------------------------
945 // name: tick_out()
946 // desc: all channels
947 //-----------------------------------------------------------------------------
948 BOOL__ DigitalOut::tick_out( const SAMPLE * samples, DWORD__ n )
950 if( !prepare_tick_out() )
951 return FALSE;
953 if( !n ) n = Digitalio::m_num_channels_out;
954 while( n-- )
955 *m_data_ptr_out++ = *samples++;
957 return TRUE;
963 //-----------------------------------------------------------------------------
964 // name: prepare_tick_out()
965 // desc: data ptr ok
966 //-----------------------------------------------------------------------------
967 inline BOOL__ DigitalOut::prepare_tick_out()
969 if( m_data_ptr_out >= m_data_max_out )
971 this->render();
974 return TRUE;
980 //-----------------------------------------------------------------------------
981 // name: render()
982 // desc: the render
983 //-----------------------------------------------------------------------------
984 DWORD__ DigitalOut::render()
986 //if( !Digitalio::m_use_cb && !Digitalio::tick() ) return FALSE;
988 if( Digitalio::m_block )
990 // synchronize
991 Digitalio::m_out_ready = TRUE;
992 // synchronize
993 while( Digitalio::m_out_ready )
994 usleep( 250 );
997 // set pointer to the beginning - if not ready, then too late anyway
998 *Digitalio::m_write_ptr = (SAMPLE *)Digitalio::m_buffer_out;
1000 return TRUE;
1006 //-----------------------------------------------------------------------------
1007 // name: DigitalIn()
1008 // desc: ...
1009 //-----------------------------------------------------------------------------
1010 DigitalIn::DigitalIn()
1012 m_data_ptr_in = NULL;
1013 m_data_max_in = NULL;
1019 //-----------------------------------------------------------------------------
1020 // name: ~DigitalIn()
1021 // desc: ...
1022 //-----------------------------------------------------------------------------
1023 DigitalIn::~DigitalIn()
1025 this->cleanup();
1031 //-----------------------------------------------------------------------------
1032 // name: initialize()
1033 // desc: initialize audio in
1034 //-----------------------------------------------------------------------------
1035 BOOL__ DigitalIn::initialize( )
1037 m_data = new SAMPLE[Digitalio::buffer_size() * Digitalio::num_channels_in()];
1038 memset( m_data, 0, Digitalio::buffer_size() * Digitalio::num_channels_in() * sizeof(SAMPLE) );
1039 #ifndef __DISABLE_RTAUDIO__
1040 // set the buffer to the beginning of the local buffer
1041 m_data_ptr_in = Digitalio::m_use_cb ? m_data
1042 : (SAMPLE *)Digitalio::audio()->getStreamBuffer();
1043 #else
1044 // set the buffer pointer
1045 assert( Digitalio::m_use_cb );
1046 m_data_ptr_in = m_data;
1047 #endif // __DISABLE_RTAUDIO__
1048 // calculate past buffer
1049 m_data_max_in = m_data_ptr_in +
1050 Digitalio::buffer_size() * Digitalio::num_channels_in();
1051 // set the read pointer to the local pointer
1052 Digitalio::m_read_ptr = &m_data_ptr_in;
1053 // invalidate
1054 m_data_ptr_in = m_data_max_in;
1056 return TRUE;
1062 //-----------------------------------------------------------------------------
1063 // name: start()
1064 // desc: ...
1065 //-----------------------------------------------------------------------------
1066 BOOL__ DigitalIn::start()
1068 return ( Digitalio::start() != 0 );
1074 //-----------------------------------------------------------------------------
1075 // name: capture_stop()
1076 // desc: ...
1077 //-----------------------------------------------------------------------------
1078 BOOL__ DigitalIn::stop()
1080 Digitalio::stop();
1081 return TRUE;
1087 //-----------------------------------------------------------------------------
1088 // name: cleanup()
1089 // desc: ...
1090 //-----------------------------------------------------------------------------
1091 void DigitalIn::cleanup()
1098 //-----------------------------------------------------------------------------
1099 // name: tick_in()
1100 // desc: ...
1101 //-----------------------------------------------------------------------------
1102 BOOL__ DigitalIn::tick_in( SAMPLE * s )
1104 if( !prepare_tick_in() )
1105 return 0;
1106 *s = *m_data_ptr_in++;
1108 return TRUE;
1114 //-----------------------------------------------------------------------------
1115 // name: tick_in()
1116 // desc: ...
1117 //-----------------------------------------------------------------------------
1118 BOOL__ DigitalIn::tick_in( SAMPLE * l, SAMPLE * r )
1120 if( !prepare_tick_in() )
1121 return FALSE;
1123 *l = *m_data_ptr_in++;
1124 *r = *m_data_ptr_in++;
1126 return TRUE;
1132 //-----------------------------------------------------------------------------
1133 // name: tick_in()
1134 // desc: ...
1135 //-----------------------------------------------------------------------------
1136 BOOL__ DigitalIn::tick_in( SAMPLE * sample, DWORD__ n )
1138 if( !prepare_tick_in() )
1139 return FALSE;
1141 if( !n ) n = Digitalio::m_num_channels_in;
1142 while( n-- )
1143 *sample++ = *m_data_ptr_in++;
1145 return TRUE;
1151 //-----------------------------------------------------------------------------
1152 // name: prepare_tick_in()
1153 // desc: data ptr ok
1154 //-----------------------------------------------------------------------------
1155 inline BOOL__ DigitalIn::prepare_tick_in()
1157 if( m_data_ptr_in >= m_data_max_in )
1159 this->capture();
1162 return TRUE;
1168 //-----------------------------------------------------------------------------
1169 // name: cb_capture()
1170 // desc: ...
1171 //-----------------------------------------------------------------------------
1172 DWORD__ DigitalIn::capture( )
1174 // if( !Digitalio::m_use_cb && !Digitalio::tick() ) return FALSE;
1176 if( Digitalio::m_block )
1178 t_CKUINT n = 20;
1179 while( !Digitalio::m_in_ready && n-- )
1180 usleep( 250 );
1183 // copy data
1184 memcpy( m_data, Digitalio::m_buffer_in, Digitalio::buffer_size() *
1185 Digitalio::num_channels_in() * sizeof(SAMPLE) );
1186 Digitalio::m_in_ready = FALSE;
1187 // set pointer to the beginning - if not ready, then too late anyway
1188 *Digitalio::m_read_ptr = (SAMPLE *)m_data;
1190 return TRUE;
1196 //-----------------------------------------------------------------------------
1197 // name: AudioBufferX()
1198 // desc: ...
1199 //-----------------------------------------------------------------------------
1200 AudioBufferX::AudioBufferX( DWORD__ size )
1202 if( size )
1203 this->initialize( size );
1204 else
1206 m_size = size;
1207 m_data = m_ptr_curr = m_ptr_end = NULL;
1214 //-----------------------------------------------------------------------------
1215 // name: initialize()
1216 // desc: ...
1217 //-----------------------------------------------------------------------------
1218 BOOL__ AudioBufferX::initialize( DWORD__ size )
1220 m_size = size;
1221 m_data = (SAMPLE *)malloc( size * sizeof(SAMPLE) );
1223 if( !m_data )
1224 return FALSE;
1226 // clear the memory
1227 memset( m_data, 0, size * sizeof(SAMPLE) );
1229 // set the pointers
1230 m_ptr_curr = m_data;
1231 m_ptr_end = m_data + size;
1233 return TRUE;
1239 //-----------------------------------------------------------------------------
1240 // name: cleanup()
1241 // desc: ...
1242 //-----------------------------------------------------------------------------
1243 void AudioBufferX::cleanup()
1245 if( m_data )
1247 free( m_data );
1248 m_data = NULL;
1251 m_size = 0;
1252 m_ptr_curr = m_ptr_end = NULL;
1258 //-----------------------------------------------------------------------------
1259 // name: size()
1260 // desc: ...
1261 //-----------------------------------------------------------------------------
1262 DWORD__ AudioBufferX::size()
1264 return m_size;
1270 //-----------------------------------------------------------------------------
1271 // name: data()
1272 // desc: ...
1273 //-----------------------------------------------------------------------------
1274 SAMPLE * AudioBufferX::data()
1276 return m_data;
1282 //-----------------------------------------------------------------------------
1283 // name: AudioBufferIn()
1284 // desc: ...
1285 //-----------------------------------------------------------------------------
1286 AudioBufferIn::AudioBufferIn( DWORD__ size )
1287 : AudioBufferX( size )
1293 //-----------------------------------------------------------------------------
1294 // name: ~AudioBufferIn()
1295 // desc: ...
1296 //-----------------------------------------------------------------------------
1297 AudioBufferIn::~AudioBufferIn()
1299 this->cleanup();
1305 //-----------------------------------------------------------------------------
1306 // name: reset()
1307 // desc: ...
1308 //-----------------------------------------------------------------------------
1309 BOOL__ AudioBufferIn::reset()
1311 m_ptr_curr = m_data;
1313 return TickIn::reset();
1319 //-----------------------------------------------------------------------------
1320 // name: tick_in()
1321 // desc: ...
1322 //-----------------------------------------------------------------------------
1323 BOOL__ AudioBufferIn::tick_in( SAMPLE * s )
1325 if( !m_data )
1326 return FALSE;
1328 *s = *m_ptr_curr++;
1330 return TRUE;
1336 //-----------------------------------------------------------------------------
1337 // name: tick_in()
1338 // desc: ...
1339 //-----------------------------------------------------------------------------
1340 BOOL__ AudioBufferIn::tick_in( SAMPLE * l, SAMPLE * r )
1342 if( !m_data || m_ptr_curr + 2 >= m_ptr_end )
1343 return FALSE;
1345 *l = *m_ptr_curr++;
1346 *r = *m_ptr_curr++;
1348 return TRUE;
1354 //-----------------------------------------------------------------------------
1355 // name: tick_in()
1356 // desc: ...
1357 //-----------------------------------------------------------------------------
1358 BOOL__ AudioBufferIn::tick_in( SAMPLE * in, DWORD__ n )
1360 if( !m_data || m_ptr_curr + n >= m_ptr_end )
1361 return FALSE;
1363 while( n-- )
1364 *in++ = *m_ptr_curr++;
1366 return TRUE;
1372 //-----------------------------------------------------------------------------
1373 // name: AudioBufferOut()
1374 // desc: ...
1375 //-----------------------------------------------------------------------------
1376 AudioBufferOut::AudioBufferOut( DWORD__ size )
1377 : AudioBufferX( size )
1383 //-----------------------------------------------------------------------------
1384 // name: ~AudioBufferOut()
1385 // desc: ...
1386 //-----------------------------------------------------------------------------
1387 AudioBufferOut::~AudioBufferOut()
1389 this->cleanup();
1395 //-----------------------------------------------------------------------------
1396 // name: reset()
1397 // desc: ...
1398 //-----------------------------------------------------------------------------
1399 BOOL__ AudioBufferOut::reset()
1401 m_ptr_curr = m_data;
1403 return TickOut::reset();
1409 //-----------------------------------------------------------------------------
1410 // name: tick_out()
1411 // desc: ...
1412 //-----------------------------------------------------------------------------
1413 BOOL__ AudioBufferOut::tick_out( SAMPLE s )
1415 if( !m_data )
1416 return FALSE;
1418 *m_ptr_curr++ = s;
1420 return TRUE;
1426 //-----------------------------------------------------------------------------
1427 // name: tick_out()
1428 // desc: ...
1429 //-----------------------------------------------------------------------------
1430 BOOL__ AudioBufferOut::tick_out( SAMPLE l, SAMPLE r )
1432 if( !m_data || m_ptr_curr + 2 >= m_ptr_end )
1433 return FALSE;
1435 *m_ptr_curr++ = l;
1436 *m_ptr_curr++ = r;
1438 return TRUE;
1444 //-----------------------------------------------------------------------------
1445 // name: tick_out()
1446 // desc: ...
1447 //-----------------------------------------------------------------------------
1448 BOOL__ AudioBufferOut::tick_out( const SAMPLE * out, DWORD__ n )
1450 if( !m_data || m_ptr_curr + n >= m_ptr_end )
1451 return FALSE;
1453 while( n-- )
1454 *m_ptr_curr++ = *out++;
1456 return TRUE;