*** empty log message ***
[chuck-blob.git] / v2 / digiio_rtaudio.cpp
blob08d0dd2108569123f80d7d53334b43c1e3c49da2
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 #include "rtaudio.h"
37 #include "rtmidi.h"
38 // #include <signal.h>
39 #if (defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__)) && !defined(__WINDOWS_PTHREAD__)
40 #include <windows.h>
41 #include <sys/timeb.h>
42 #else
43 #include <unistd.h>
44 #include <sys/time.h>
45 #endif
47 // extern "C" void signal_int( int );
49 // static
50 BOOL__ Digitalio::m_init = FALSE;
51 DWORD__ Digitalio::m_start = 0;
52 DWORD__ Digitalio::m_tick_count = 0;
53 DWORD__ Digitalio::m_num_channels_out = NUM_CHANNELS_DEFAULT;
54 DWORD__ Digitalio::m_num_channels_in = NUM_CHANNELS_DEFAULT;
55 DWORD__ Digitalio::m_sampling_rate = SAMPLING_RATE_DEFAULT;
56 DWORD__ Digitalio::m_bps = BITS_PER_SAMPLE_DEFAULT;
57 DWORD__ Digitalio::m_buffer_size = BUFFER_SIZE_DEFAULT;
58 DWORD__ Digitalio::m_num_buffers = NUM_BUFFERS_DEFAULT;
59 RtAudio * Digitalio::m_rtaudio = NULL;
60 SAMPLE * Digitalio::m_buffer_out = NULL;
61 SAMPLE * Digitalio::m_buffer_in = NULL;
62 SAMPLE ** Digitalio::m_write_ptr = NULL;
63 SAMPLE ** Digitalio::m_read_ptr = NULL;
64 SAMPLE * Digitalio::m_extern_in = NULL;
65 SAMPLE * Digitalio::m_extern_out = NULL;
66 BOOL__ Digitalio::m_out_ready = FALSE;
67 BOOL__ Digitalio::m_in_ready = FALSE;
68 BOOL__ Digitalio::m_use_cb = USE_CB_DEFAULT;
69 DWORD__ Digitalio::m_go = 0;
70 DWORD__ Digitalio::m_dac_n = 0;
71 DWORD__ Digitalio::m_adc_n = 0;
72 DWORD__ Digitalio::m_end = 0;
73 DWORD__ Digitalio::m_block = TRUE;
74 DWORD__ Digitalio::m_xrun = 0;
77 // sample
78 #if defined(CK_S_DOUBLE)
79 #define CK_RTAUDIO_FORMAT RTAUDIO_FLOAT64
80 #else
81 #define CK_RTAUDIO_FORMAT RTAUDIO_FLOAT32
82 #endif
87 //-----------------------------------------------------------------------------
88 // name: print()
89 // desc: ...
90 //-----------------------------------------------------------------------------
91 void print( const RtAudioDeviceInfo & info )
93 EM_error2b( 0, "device name = \"%s\"", info.name.c_str() );
94 if (info.probed == false)
95 EM_error2b( 0, "probe [failed] ..." );
96 else
98 EM_error2b( 0, "probe [success] ..." );
99 EM_error2b( 0, "# output channels = %d", info.outputChannels );
100 EM_error2b( 0, "# input channels = %d", info.inputChannels );
101 EM_error2b( 0, "# duplex Channels = %d", info.duplexChannels );
102 if( info.isDefault ) EM_error2b( 0, "default device = YES" );
103 else EM_error2b( 0, "default device = NO" );
104 if( info.nativeFormats == 0 ) EM_error2b( 0, "no natively supported data formats(?)!" );
105 else
107 EM_error2b( 0, "natively supported data formats:" );
108 if( info.nativeFormats & RTAUDIO_SINT8 ) EM_error2b( 0, " 8-bit int" );
109 if( info.nativeFormats & RTAUDIO_SINT16 ) EM_error2b( 0, " 16-bit int" );
110 if( info.nativeFormats & RTAUDIO_SINT24 ) EM_error2b( 0, " 24-bit int" );
111 if( info.nativeFormats & RTAUDIO_SINT32 ) EM_error2b( 0, " 32-bit int" );
112 if( info.nativeFormats & RTAUDIO_FLOAT32 ) EM_error2b( 0, " 32-bit float" );
113 if( info.nativeFormats & RTAUDIO_FLOAT64 ) EM_error2b( 0, " 64-bit float" );
115 if ( info.sampleRates.size() < 1 ) EM_error2b( 0,"no supported sample rates found!" );
116 else
118 EM_error2b( 0, "supported sample rates:" );
119 for( unsigned int j = 0; j < info.sampleRates.size(); j++ )
120 EM_error2b( 0, " %d Hz", info.sampleRates[j] );
128 //-----------------------------------------------------------------------------
129 // name: probe()
130 // desc: ...
131 //-----------------------------------------------------------------------------
132 void Digitalio::probe()
134 RtAudio * rta = NULL;
135 RtAudioDeviceInfo info;
137 // allocate RtAudio
138 try { rta = new RtAudio( ); }
139 catch( RtError err )
141 // problem finding audio devices, most likely
142 EM_error2b( 0, "%s", err.getMessageString() );
143 return;
146 // get count
147 int devices = rta->getDeviceCount();
148 EM_error2b( 0, "found %d device(s) ...", devices );
149 // EM_error2( 0, "--------------------------" );
151 // loop
152 for( int i = 1; i <= devices; i++ )
154 try { info = rta->getDeviceInfo(i); }
155 catch( RtError & error )
157 error.printMessage();
158 break;
161 // print
162 EM_error2b( 0, "------( chuck -- dac%d )---------------", i );
163 print( info );
164 // skip
165 if( i < devices ) EM_error2( 0, "" );
168 delete rta;
170 return;
176 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
177 //-----------------------------------------------------------------------------
178 // name: set_priority()
179 // desc: ...
180 //-----------------------------------------------------------------------------
181 static t_CKBOOL set_priority( CHUCK_THREAD tid, t_CKINT priority )
183 struct sched_param param;
184 int policy;
186 // log
187 EM_log( CK_LOG_FINE, "setting thread priority to: %ld...", priority );
189 // get for thread
190 if( pthread_getschedparam( tid, &policy, &param) )
191 return FALSE;
193 // priority
194 param.sched_priority = priority;
195 // policy
196 policy = SCHED_RR;
197 // set for thread
198 if( pthread_setschedparam( tid, policy, &param ) )
199 return FALSE;
201 return TRUE;
203 #else
204 //-----------------------------------------------------------------------------
205 // name: set_priority()
206 // desc: ...
207 //-----------------------------------------------------------------------------
208 static t_CKBOOL set_priority( CHUCK_THREAD tid, t_CKINT priority )
210 // if priority is 0 then done
211 if( !priority ) return TRUE;
213 // log
214 EM_log( CK_LOG_FINE, "setting thread priority to: %ld...", priority );
216 // set the priority the thread
217 if( !SetThreadPriority( tid, priority ) )
218 return FALSE;
220 return TRUE;
222 #endif
225 //-----------------------------------------------------------------------------
226 // name: get_current_time()
227 // desc: ...
228 //-----------------------------------------------------------------------------
229 static t_CKFLOAT get_current_time( t_CKBOOL fresh = TRUE )
231 #ifdef __PLATFORM_WIN32__
232 struct _timeb t;
233 _ftime(&t);
234 return t.time + t.millitm/1000.0;
235 #else
236 static struct timeval t;
237 if( fresh ) gettimeofday(&t,NULL);
238 return t.tv_sec + (t_CKFLOAT)t.tv_usec/1000000;
239 #endif
241 return 0;
245 // watch dog globals
246 static CHUCK_THREAD g_tid_synthesis = 0;
247 static XThread * g_watchdog_thread = NULL;
248 static t_CKBOOL g_watchdog_state = FALSE;
249 static t_CKFLOAT g_watchdog_time = 0;
252 //-----------------------------------------------------------------------------
253 // name: watch_dog()
254 // desc: ...
255 //-----------------------------------------------------------------------------
256 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
257 static void * watch_dog( void * )
258 #else
259 static unsigned int __stdcall watch_dog( void * )
260 #endif
262 t_CKFLOAT time;
264 // boost priority?
265 t_CKUINT priority = Chuck_VM::our_priority;
267 // log
268 EM_log( CK_LOG_SEVERE, "starting real-time watch dog processs..." );
269 // push log
270 EM_pushlog();
271 EM_log( CK_LOG_INFO, "watchdog timeout: %f::second", g_watchdog_timeout );
272 EM_log( CK_LOG_INFO, "watchdog thread priority: %d", priority );
273 EM_log( CK_LOG_INFO, "watchdog countermeasure priority: %d", g_watchdog_countermeasure_priority );
274 // pop log
275 EM_poplog();
277 // boost watchdog by same priority
278 if( Chuck_VM::our_priority != 0x7fffffff )
279 Chuck_VM::set_priority( priority, NULL );
281 // while going
282 while( g_do_watchdog )
284 // get
285 time = get_current_time( TRUE );
286 // fprintf( stderr, "last: %f now: %f\n", g_watchdog_time, time );
288 // resting
289 if( g_watchdog_state == FALSE )
291 // check xrun
292 // if( Digitalio::m_xrun > 100 )
293 if( time - g_watchdog_time > g_watchdog_timeout )
295 // log
296 EM_log( CK_LOG_SEVERE, "real-time watchdog counter-measure activating..." );
297 // lowering priority
298 if( g_tid_synthesis && Chuck_VM::our_priority != 0x7fffffff )
299 set_priority( g_tid_synthesis, g_watchdog_countermeasure_priority );
300 // set state
301 g_watchdog_state = TRUE;
304 else
306 // check xrun
307 // if( Digitalio::m_xrun == 0 )
308 if( time - g_watchdog_time < g_watchdog_timeout )
310 // log
311 EM_log( CK_LOG_SEVERE, "real-time watchdog resting..." );
312 // raise priority
313 if( g_tid_synthesis && Chuck_VM::our_priority != 0x7fffffff )
314 set_priority( g_tid_synthesis, Chuck_VM::our_priority );
315 // set state
316 g_watchdog_state = FALSE;
320 // advance time
321 usleep( 40000 );
324 // log
325 EM_log( CK_LOG_SEVERE, "stopping real-time watch dog process..." );
327 return 0;
333 //-----------------------------------------------------------------------------
334 // name: watchdog_start()
335 // desc: ...
336 //-----------------------------------------------------------------------------
337 BOOL__ Digitalio::watchdog_start()
339 // already
340 if( g_watchdog_thread )
341 return FALSE;
343 // flag
344 g_do_watchdog = TRUE;
345 // allocate it
346 g_watchdog_thread = new XThread;
347 // start it
348 g_watchdog_thread->start( watch_dog, NULL );
350 return TRUE;
355 //-----------------------------------------------------------------------------
356 // name: watchdog_stop()
357 // desc: ...
358 //-----------------------------------------------------------------------------
359 BOOL__ Digitalio::watchdog_stop()
361 // already
362 if( !g_watchdog_thread )
363 return FALSE;
365 // stop things
366 g_do_watchdog = FALSE;
367 // wait a bit
368 // usleep( 100000 )
369 SAFE_DELETE( g_watchdog_thread );
371 return TRUE;
377 //-----------------------------------------------------------------------------
378 // name: initialize()
379 // desc: ...
380 //-----------------------------------------------------------------------------
381 BOOL__ Digitalio::initialize( DWORD__ num_dac_channels,
382 DWORD__ num_adc_channels,
383 DWORD__ sampling_rate,
384 DWORD__ bps, DWORD__ buffer_size,
385 DWORD__ num_buffers, DWORD__ block,
386 Chuck_VM * vm_ref, BOOL__ rt_audio,
387 void * callback, void * data )
389 if( m_init )
390 return FALSE;
392 m_num_channels_out = num_dac_channels;
393 m_num_channels_in = num_adc_channels;
394 m_sampling_rate = sampling_rate;
395 m_bps = bps;
396 m_buffer_size = buffer_size;
397 m_num_buffers = num_buffers;
398 m_start = 0;
399 m_tick_count = 0;
400 m_go = 0;
401 m_end = 0;
402 m_block = block;
404 DWORD__ num_channels;
405 int bufsize = m_buffer_size;
407 // if rt_audio is false, then set block to FALSE to avoid deadlock
408 if( !rt_audio ) m_block = FALSE;
410 // if real-time audio
411 if( rt_audio )
413 // allocate RtAudio
414 try { m_rtaudio = new RtAudio( ); }
415 catch( RtError err )
417 // problem finding audio devices, most likely
418 EM_error2( 0, "%s", err.getMessageString() );
419 return m_init = FALSE;
422 // log
423 EM_log( CK_LOG_FINE, "initializing RtAudio..." );
424 // push indent
425 EM_pushlog();
427 // open device
428 try {
429 // log
430 EM_log( CK_LOG_FINE, "trying %d input %d output...",
431 m_num_channels_in, m_num_channels_out );
432 // open RtAudio
433 m_rtaudio->openStream(
434 m_dac_n, m_num_channels_out, m_adc_n, m_num_channels_in,
435 CK_RTAUDIO_FORMAT, sampling_rate,
436 &bufsize, num_buffers );
437 // set callback
438 if( m_use_cb )
440 // log
441 EM_log( CK_LOG_INFO, "initializing callback..." );
442 if( !callback )
444 if( block ) m_rtaudio->setStreamCallback( &cb, vm_ref );
445 else m_rtaudio->setStreamCallback( &cb2, vm_ref );
447 else
449 m_rtaudio->setStreamCallback( (RtAudioCallback)callback, data );
452 } catch( RtError err ) {
453 // log
454 EM_log( CK_LOG_INFO, "exception caught: '%s'...", err.getMessageString() );
455 EM_log( CK_LOG_INFO, "trying %d input %d output...", 0, m_num_channels_out );
456 try {
457 bufsize = buffer_size;
458 // try output only
459 m_rtaudio->openStream(
460 m_dac_n, m_num_channels_out, 0, 0,
461 RTAUDIO_FLOAT32, sampling_rate,
462 &bufsize, num_buffers );
463 // set callback
464 if( m_use_cb )
466 // log
467 EM_log( CK_LOG_INFO, "initializing callback (again)..." );
468 if( !callback )
470 if( block ) m_rtaudio->setStreamCallback( &cb, vm_ref );
471 else m_rtaudio->setStreamCallback( &cb2, vm_ref );
473 else
475 m_rtaudio->setStreamCallback( (RtAudioCallback)callback, data );
478 } catch( RtError err ) {
479 EM_error2( 0, "%s", err.getMessageString() );
480 SAFE_DELETE( m_rtaudio );
481 return m_init = FALSE;
485 // check bufsize
486 if( bufsize != (int)m_buffer_size )
488 EM_log( CK_LOG_SEVERE, "new buffer size: %d -> %i", m_buffer_size, bufsize );
489 m_buffer_size = bufsize;
492 // pop indent
493 EM_poplog();
496 if( m_use_cb )
498 num_channels = num_dac_channels > num_adc_channels ?
499 num_dac_channels : num_adc_channels;
500 // log
501 EM_log( CK_LOG_SEVERE, "allocating buffers for %d x %d samples...",
502 m_buffer_size, num_channels );
503 // allocate buffers
504 m_buffer_in = new SAMPLE[m_buffer_size * num_channels];
505 m_buffer_out = new SAMPLE[m_buffer_size * num_channels];
506 memset( m_buffer_in, 0, m_buffer_size * sizeof(SAMPLE) * num_channels );
507 memset( m_buffer_out, 0, m_buffer_size * sizeof(SAMPLE) * num_channels );
508 m_read_ptr = NULL;
509 m_write_ptr = NULL;
512 m_in_ready = FALSE;
513 m_out_ready = FALSE;
515 return m_init = TRUE;
521 //-----------------------------------------------------------------------------
522 // name: cb()
523 // desc: ...
524 //-----------------------------------------------------------------------------
525 int Digitalio::cb( char * buffer, int buffer_size, void * user_data )
527 DWORD__ len = buffer_size * sizeof(SAMPLE) * m_num_channels_out;
528 DWORD__ n = 20;
529 DWORD__ start = 50;
531 // copy input to local buffer
532 if( m_num_channels_in )
534 memcpy( m_buffer_in, buffer, len );
535 // copy to extern
536 if( m_extern_in ) memcpy( m_extern_in, buffer, len );
538 // flag ready
539 m_in_ready = TRUE;
540 // out is ready early
541 if( m_go < start && m_go > 1 && m_out_ready ) m_go = start;
542 // copy output into local buffer
543 if( m_go >= start )
545 while( !m_out_ready && n-- ) usleep( 250 );
546 if( m_out_ready && g_do_watchdog )
547 g_watchdog_time = get_current_time( TRUE );
548 // copy local buffer to be rendered
549 if( m_out_ready && !m_end ) memcpy( buffer, m_buffer_out, len );
550 // set all elements of local buffer to silence
551 else memset( buffer, 0, len );
553 else // initial condition
555 // priority boost
556 if( !m_go && Chuck_VM::our_priority != 0x7fffffff )
557 Chuck_VM::set_priority( Chuck_VM::our_priority, NULL );
558 // catch SIGINT
559 // signal( SIGINT, signal_int );
561 // timestamp
562 if( g_do_watchdog ) g_watchdog_time = get_current_time( TRUE );
564 memset( buffer, 0, len );
565 m_go++;
566 return 0;
569 // 2nd buffer
570 if( m_go == start )
572 n = 8; while( !m_out_ready && n-- ) usleep( 250 );
573 len /= sizeof(SAMPLE); DWORD__ i = 0;
574 SAMPLE * s = (SAMPLE *)buffer;
575 while( i < len ) *s++ *= (SAMPLE)i++/len;
576 m_go++;
579 // copy to extern
580 if( m_extern_out ) memcpy( m_extern_out, buffer, len );
582 // set pointer to the beginning - if not ready, then too late anyway
583 //*m_write_ptr = (SAMPLE *)m_buffer_out;
584 //*m_read_ptr = (SAMPLE *)m_buffer_in;
585 m_out_ready = FALSE;
587 return 0;
593 //-----------------------------------------------------------------------------
594 // name: cb2()
595 // desc: ...
596 //-----------------------------------------------------------------------------
597 int Digitalio::cb2( char * buffer, int buffer_size, void * user_data )
599 DWORD__ len = buffer_size * sizeof(SAMPLE) * m_num_channels_out;
600 Chuck_VM * vm_ref = (Chuck_VM *)user_data;
602 // priority boost
603 if( !m_go && Chuck_VM::our_priority != 0x7fffffff )
605 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
606 g_tid_synthesis = pthread_self();
607 #else
608 // must duplicate for handle to be usable by other threads
609 g_tid_synthesis = NULL;
610 DuplicateHandle(
611 GetCurrentProcess(),
612 GetCurrentThread(),
613 GetCurrentProcess(),
614 &g_tid_synthesis,
616 FALSE,
617 DUPLICATE_SAME_ACCESS
620 // TODO: close the duplicate handle?
621 #endif
622 Chuck_VM::set_priority( Chuck_VM::our_priority, NULL );
623 memset( buffer, 0, len );
624 m_go = TRUE;
626 // start watchdog
627 if( g_do_watchdog )
629 // timestamp
630 g_watchdog_time = get_current_time( TRUE );
631 // start watchdog
632 watchdog_start();
635 // let it go the first time
636 return 0;
639 // copy input to local buffer
640 if( m_num_channels_in )
642 memcpy( m_buffer_in, buffer, len );
643 // copy to extern
644 if( m_extern_in ) memcpy( m_extern_in, buffer, len );
647 // check xrun
648 if( m_xrun < 6 )
650 // timestamp
651 if( g_do_watchdog ) g_watchdog_time = get_current_time( TRUE );
652 // get samples from output
653 vm_ref->run( buffer_size );
654 // ...
655 if( m_xrun ) m_xrun--;
657 else
659 // reset
660 m_xrun /= 2;
663 // copy local buffer to be rendered
664 if( !m_end ) memcpy( buffer, m_buffer_out, len );
665 // set all elements of local buffer to silence
666 else memset( buffer, 0, len );
668 // copy to extern
669 if( m_extern_out ) memcpy( m_extern_out, buffer, len );
672 return 0;
678 //-----------------------------------------------------------------------------
679 // name: start()
680 // desc: ...
681 //-----------------------------------------------------------------------------
682 BOOL__ Digitalio::start( )
684 try{ if( !m_start )
685 m_rtaudio->startStream();
686 m_start = TRUE;
687 } catch( RtError err ){ return FALSE; }
689 return m_start;
695 //-----------------------------------------------------------------------------
696 // name: stop()
697 // desc: ...
698 //-----------------------------------------------------------------------------
699 BOOL__ Digitalio::stop( )
701 try{ if( m_start )
702 m_rtaudio->stopStream();
703 m_start = FALSE;
704 } catch( RtError err ){ return FALSE; }
706 return !m_start;
712 //-----------------------------------------------------------------------------
713 // name: tick()
714 // desc: ...
715 //-----------------------------------------------------------------------------
716 BOOL__ Digitalio::tick( )
720 if( ++m_tick_count >= m_start )
722 m_rtaudio->tickStream();
723 m_tick_count = 0;
724 m_out_ready = TRUE;
725 m_in_ready = TRUE;
728 return TRUE;
729 } catch( RtError err ){ return FALSE; }
735 //-----------------------------------------------------------------------------
736 // name: shutdown()
737 // desc: ...
738 //-----------------------------------------------------------------------------
739 void Digitalio::shutdown()
741 if( !m_init ) return;
742 if( m_start )
744 if( m_use_cb ) m_rtaudio->cancelStreamCallback();
745 m_rtaudio->stopStream();
748 m_rtaudio->closeStream();
749 SAFE_DELETE( m_rtaudio );
750 m_init = FALSE;
751 m_start = FALSE;
753 // stop watchdog
754 watchdog_stop();
760 //-----------------------------------------------------------------------------
761 // name: DigitalOut()
762 // desc: ...
763 //-----------------------------------------------------------------------------
764 DigitalOut::DigitalOut()
766 m_data_ptr_out = NULL;
767 m_data_max_out = NULL;
773 //-----------------------------------------------------------------------------
774 // name: ~DigitalOut()
775 // desc: ...
776 //-----------------------------------------------------------------------------
777 DigitalOut::~DigitalOut()
779 this->cleanup();
785 //-----------------------------------------------------------------------------
786 // name: initialize()
787 // desc: initialize audio out
788 //-----------------------------------------------------------------------------
789 BOOL__ DigitalOut::initialize( )
791 // set pointer to beginning of local buffer
792 m_data_ptr_out = Digitalio::m_use_cb ? Digitalio::m_buffer_out
793 : (SAMPLE *)Digitalio::audio()->getStreamBuffer();
794 // calculate the end of the buffer
795 m_data_max_out = m_data_ptr_out +
796 Digitalio::buffer_size() * Digitalio::num_channels_out();
797 // set the writer pointer to our write pointer
798 Digitalio::m_write_ptr = &m_data_ptr_out;
800 return TRUE;
806 //-----------------------------------------------------------------------------
807 // name: start()
808 // desc: render
809 //-----------------------------------------------------------------------------
810 BOOL__ DigitalOut::start()
812 // start stream
813 return ( Digitalio::start() != 0 );
819 //-----------------------------------------------------------------------------
820 // name: stop()
821 // desc: render
822 //-----------------------------------------------------------------------------
823 BOOL__ DigitalOut::stop()
825 // well
826 Digitalio::stop();
828 return TRUE;
834 //-----------------------------------------------------------------------------
835 // name: cleanup()
836 // desc: ...
837 //-----------------------------------------------------------------------------
838 void DigitalOut::cleanup()
845 //-----------------------------------------------------------------------------
846 // name: tick_out()
847 // desc: 1 channel
848 //-----------------------------------------------------------------------------
849 BOOL__ DigitalOut::tick_out( SAMPLE sample )
851 if( !prepare_tick_out() )
852 return FALSE;
854 *m_data_ptr_out++ = sample;
856 return TRUE;
862 //-----------------------------------------------------------------------------
863 // name: tick_out()
864 // desc: 2 channel
865 //-----------------------------------------------------------------------------
866 BOOL__ DigitalOut::tick_out( SAMPLE sample_l, SAMPLE sample_r )
868 if( !prepare_tick_out() )
869 return FALSE;
871 *m_data_ptr_out++ = sample_l;
872 *m_data_ptr_out++ = sample_r;
874 return TRUE;
880 //-----------------------------------------------------------------------------
881 // name: tick_out()
882 // desc: all channels
883 //-----------------------------------------------------------------------------
884 BOOL__ DigitalOut::tick_out( const SAMPLE * samples, DWORD__ n )
886 if( !prepare_tick_out() )
887 return FALSE;
889 if( !n ) n = Digitalio::m_num_channels_out;
890 while( n-- )
891 *m_data_ptr_out++ = *samples++;
893 return TRUE;
899 //-----------------------------------------------------------------------------
900 // name: prepare_tick_out()
901 // desc: data ptr ok
902 //-----------------------------------------------------------------------------
903 inline BOOL__ DigitalOut::prepare_tick_out()
905 if( m_data_ptr_out >= m_data_max_out )
907 this->render();
910 return TRUE;
916 //-----------------------------------------------------------------------------
917 // name: render()
918 // desc: the render
919 //-----------------------------------------------------------------------------
920 DWORD__ DigitalOut::render()
922 //if( !Digitalio::m_use_cb && !Digitalio::tick() ) return FALSE;
924 if( Digitalio::m_block )
926 // synchronize
927 Digitalio::m_out_ready = TRUE;
928 // synchronize
929 while( Digitalio::m_out_ready )
930 usleep( 250 );
933 // set pointer to the beginning - if not ready, then too late anyway
934 *Digitalio::m_write_ptr = (SAMPLE *)Digitalio::m_buffer_out;
936 return TRUE;
942 //-----------------------------------------------------------------------------
943 // name: DigitalIn()
944 // desc: ...
945 //-----------------------------------------------------------------------------
946 DigitalIn::DigitalIn()
948 m_data_ptr_in = NULL;
949 m_data_max_in = NULL;
955 //-----------------------------------------------------------------------------
956 // name: ~DigitalIn()
957 // desc: ...
958 //-----------------------------------------------------------------------------
959 DigitalIn::~DigitalIn()
961 this->cleanup();
967 //-----------------------------------------------------------------------------
968 // name: initialize()
969 // desc: initialize audio in
970 //-----------------------------------------------------------------------------
971 BOOL__ DigitalIn::initialize( )
973 m_data = new SAMPLE[Digitalio::buffer_size() * Digitalio::num_channels_in()];
974 memset( m_data, 0, Digitalio::buffer_size() * Digitalio::num_channels_in() * sizeof(SAMPLE) );
975 // set the buffer to the beginning of the local buffer
976 m_data_ptr_in = Digitalio::m_use_cb ? m_data
977 : (SAMPLE *)Digitalio::audio()->getStreamBuffer();
978 // calculate past buffer
979 m_data_max_in = m_data_ptr_in +
980 Digitalio::buffer_size() * Digitalio::num_channels_in();
981 // set the read pointer to the local pointer
982 Digitalio::m_read_ptr = &m_data_ptr_in;
983 // invalidate
984 m_data_ptr_in = m_data_max_in;
986 return TRUE;
992 //-----------------------------------------------------------------------------
993 // name: start()
994 // desc: ...
995 //-----------------------------------------------------------------------------
996 BOOL__ DigitalIn::start()
998 return ( Digitalio::start() != 0 );
1004 //-----------------------------------------------------------------------------
1005 // name: capture_stop()
1006 // desc: ...
1007 //-----------------------------------------------------------------------------
1008 BOOL__ DigitalIn::stop()
1010 Digitalio::stop();
1011 return TRUE;
1017 //-----------------------------------------------------------------------------
1018 // name: cleanup()
1019 // desc: ...
1020 //-----------------------------------------------------------------------------
1021 void DigitalIn::cleanup()
1028 //-----------------------------------------------------------------------------
1029 // name: tick_in()
1030 // desc: ...
1031 //-----------------------------------------------------------------------------
1032 BOOL__ DigitalIn::tick_in( SAMPLE * s )
1034 if( !prepare_tick_in() )
1035 return 0;
1036 *s = *m_data_ptr_in++;
1038 return TRUE;
1044 //-----------------------------------------------------------------------------
1045 // name: tick_in()
1046 // desc: ...
1047 //-----------------------------------------------------------------------------
1048 BOOL__ DigitalIn::tick_in( SAMPLE * l, SAMPLE * r )
1050 if( !prepare_tick_in() )
1051 return FALSE;
1053 *l = *m_data_ptr_in++;
1054 *r = *m_data_ptr_in++;
1056 return TRUE;
1062 //-----------------------------------------------------------------------------
1063 // name: tick_in()
1064 // desc: ...
1065 //-----------------------------------------------------------------------------
1066 BOOL__ DigitalIn::tick_in( SAMPLE * sample, DWORD__ n )
1068 if( !prepare_tick_in() )
1069 return FALSE;
1071 if( !n ) n = Digitalio::m_num_channels_in;
1072 while( n-- )
1073 *sample++ = *m_data_ptr_in++;
1075 return TRUE;
1081 //-----------------------------------------------------------------------------
1082 // name: prepare_tick_in()
1083 // desc: data ptr ok
1084 //-----------------------------------------------------------------------------
1085 inline BOOL__ DigitalIn::prepare_tick_in()
1087 if( m_data_ptr_in >= m_data_max_in )
1089 this->capture();
1092 return TRUE;
1098 //-----------------------------------------------------------------------------
1099 // name: cb_capture()
1100 // desc: ...
1101 //-----------------------------------------------------------------------------
1102 DWORD__ DigitalIn::capture( )
1104 // if( !Digitalio::m_use_cb && !Digitalio::tick() ) return FALSE;
1106 if( Digitalio::m_block )
1108 t_CKUINT n = 20;
1109 while( !Digitalio::m_in_ready && n-- )
1110 usleep( 250 );
1113 // copy data
1114 memcpy( m_data, Digitalio::m_buffer_in, Digitalio::buffer_size() *
1115 Digitalio::num_channels_in() * sizeof(SAMPLE) );
1116 Digitalio::m_in_ready = FALSE;
1117 // set pointer to the beginning - if not ready, then too late anyway
1118 *Digitalio::m_read_ptr = (SAMPLE *)m_data;
1120 return TRUE;
1126 //-----------------------------------------------------------------------------
1127 // name: AudioBufferX()
1128 // desc: ...
1129 //-----------------------------------------------------------------------------
1130 AudioBufferX::AudioBufferX( DWORD__ size )
1132 if( size )
1133 this->initialize( size );
1134 else
1136 m_size = size;
1137 m_data = m_ptr_curr = m_ptr_end = NULL;
1144 //-----------------------------------------------------------------------------
1145 // name: initialize()
1146 // desc: ...
1147 //-----------------------------------------------------------------------------
1148 BOOL__ AudioBufferX::initialize( DWORD__ size )
1150 m_size = size;
1151 m_data = (SAMPLE *)malloc( size * sizeof(SAMPLE) );
1153 if( !m_data )
1154 return FALSE;
1156 // clear the memory
1157 memset( m_data, 0, size * sizeof(SAMPLE) );
1159 // set the pointers
1160 m_ptr_curr = m_data;
1161 m_ptr_end = m_data + size;
1163 return TRUE;
1169 //-----------------------------------------------------------------------------
1170 // name: cleanup()
1171 // desc: ...
1172 //-----------------------------------------------------------------------------
1173 void AudioBufferX::cleanup()
1175 if( m_data )
1177 free( m_data );
1178 m_data = NULL;
1181 m_size = 0;
1182 m_ptr_curr = m_ptr_end = NULL;
1188 //-----------------------------------------------------------------------------
1189 // name: size()
1190 // desc: ...
1191 //-----------------------------------------------------------------------------
1192 DWORD__ AudioBufferX::size()
1194 return m_size;
1200 //-----------------------------------------------------------------------------
1201 // name: data()
1202 // desc: ...
1203 //-----------------------------------------------------------------------------
1204 SAMPLE * AudioBufferX::data()
1206 return m_data;
1212 //-----------------------------------------------------------------------------
1213 // name: AudioBufferIn()
1214 // desc: ...
1215 //-----------------------------------------------------------------------------
1216 AudioBufferIn::AudioBufferIn( DWORD__ size )
1217 : AudioBufferX( size )
1223 //-----------------------------------------------------------------------------
1224 // name: ~AudioBufferIn()
1225 // desc: ...
1226 //-----------------------------------------------------------------------------
1227 AudioBufferIn::~AudioBufferIn()
1229 this->cleanup();
1235 //-----------------------------------------------------------------------------
1236 // name: reset()
1237 // desc: ...
1238 //-----------------------------------------------------------------------------
1239 BOOL__ AudioBufferIn::reset()
1241 m_ptr_curr = m_data;
1243 return TickIn::reset();
1249 //-----------------------------------------------------------------------------
1250 // name: tick_in()
1251 // desc: ...
1252 //-----------------------------------------------------------------------------
1253 BOOL__ AudioBufferIn::tick_in( SAMPLE * s )
1255 if( !m_data )
1256 return FALSE;
1258 *s = *m_ptr_curr++;
1260 return TRUE;
1266 //-----------------------------------------------------------------------------
1267 // name: tick_in()
1268 // desc: ...
1269 //-----------------------------------------------------------------------------
1270 BOOL__ AudioBufferIn::tick_in( SAMPLE * l, SAMPLE * r )
1272 if( !m_data || m_ptr_curr + 2 >= m_ptr_end )
1273 return FALSE;
1275 *l = *m_ptr_curr++;
1276 *r = *m_ptr_curr++;
1278 return TRUE;
1284 //-----------------------------------------------------------------------------
1285 // name: tick_in()
1286 // desc: ...
1287 //-----------------------------------------------------------------------------
1288 BOOL__ AudioBufferIn::tick_in( SAMPLE * in, DWORD__ n )
1290 if( !m_data || m_ptr_curr + n >= m_ptr_end )
1291 return FALSE;
1293 while( n-- )
1294 *in++ = *m_ptr_curr++;
1296 return TRUE;
1302 //-----------------------------------------------------------------------------
1303 // name: AudioBufferOut()
1304 // desc: ...
1305 //-----------------------------------------------------------------------------
1306 AudioBufferOut::AudioBufferOut( DWORD__ size )
1307 : AudioBufferX( size )
1313 //-----------------------------------------------------------------------------
1314 // name: ~AudioBufferOut()
1315 // desc: ...
1316 //-----------------------------------------------------------------------------
1317 AudioBufferOut::~AudioBufferOut()
1319 this->cleanup();
1325 //-----------------------------------------------------------------------------
1326 // name: reset()
1327 // desc: ...
1328 //-----------------------------------------------------------------------------
1329 BOOL__ AudioBufferOut::reset()
1331 m_ptr_curr = m_data;
1333 return TickOut::reset();
1339 //-----------------------------------------------------------------------------
1340 // name: tick_out()
1341 // desc: ...
1342 //-----------------------------------------------------------------------------
1343 BOOL__ AudioBufferOut::tick_out( SAMPLE s )
1345 if( !m_data )
1346 return FALSE;
1348 *m_ptr_curr++ = s;
1350 return TRUE;
1356 //-----------------------------------------------------------------------------
1357 // name: tick_out()
1358 // desc: ...
1359 //-----------------------------------------------------------------------------
1360 BOOL__ AudioBufferOut::tick_out( SAMPLE l, SAMPLE r )
1362 if( !m_data || m_ptr_curr + 2 >= m_ptr_end )
1363 return FALSE;
1365 *m_ptr_curr++ = l;
1366 *m_ptr_curr++ = r;
1368 return TRUE;
1374 //-----------------------------------------------------------------------------
1375 // name: tick_out()
1376 // desc: ...
1377 //-----------------------------------------------------------------------------
1378 BOOL__ AudioBufferOut::tick_out( const SAMPLE * out, DWORD__ n )
1380 if( !m_data || m_ptr_curr + n >= m_ptr_end )
1381 return FALSE;
1383 while( n-- )
1384 *m_ptr_curr++ = *out++;
1386 return TRUE;