1163 lines · 38.3 KB · C++
RawDownload
/*----------------------------------------------------------------------------  ChucK Concurrent, On-the-fly Audio Programming Language    Compiler and Virtual Machine   Copyright (c) 2004 Ge Wang and Perry R. Cook.  All rights reserved.    http://chuck.stanford.edu/    http://chuck.cs.princeton.edu/   This program is free software; you can redistribute it and/or modify  it under the terms of the GNU General Public License as published by  the Free Software Foundation; either version 2 of the License, or  (at your option) any later version.   This program is distributed in the hope that it will be useful,  but WITHOUT ANY WARRANTY; without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  GNU General Public License for more details.   You should have received a copy of the GNU General Public License  along with this program; if not, write to the Free Software  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  U.S.A.-----------------------------------------------------------------------------*/ //-----------------------------------------------------------------------------// name: chuck_audio.cpp// desc: chuck host digital audio I/O, using RtAudio//// author: Ge Wang (ge@ccrma.stanford.edu | gewang@cs.princeton.edu)//         Spencer Salazar (spencer@ccrma.stanford.edu)// RtAudio by: Gary Scavone//// date: Spring 2004 -- initial versions//       Fall 2017 -- REFACTOR-2017: clean up to be more modular//-----------------------------------------------------------------------------#include "chuck_audio.h"#include "chuck_errmsg.h"#include "util_thread.h"#include <limits.h>#include "rtmidi.h" #if (defined(__PLATFORM_WIN32__) && !defined(__WINDOWS_PTHREAD__))  #include <windows.h>  #include <sys/timeb.h>#else  #include <unistd.h>  #include <sys/time.h>#endif    // sample#if defined(__CHUCK_USE_64_BIT_SAMPLE__)#define CK_RTAUDIO_FORMAT RTAUDIO_FLOAT64#else#define CK_RTAUDIO_FORMAT RTAUDIO_FLOAT32#endif    // real-time watch dogt_CKBOOL g_do_watchdog = FALSE;// countermeasure#ifdef __MACOSX_CORE__t_CKUINT g_watchdog_countermeasure_priority = 10;#elif defined(__PLATFORM_WIN32__) && !defined(__WINDOWS_PTHREAD__)t_CKUINT g_watchdog_countermeasure_priority = THREAD_PRIORITY_LOWEST;#elset_CKUINT g_watchdog_countermeasure_priority = 0;#endif// watchdog timeoutt_CKFLOAT g_watchdog_timeout = 0.5;    // static initializationt_CKBOOL ChuckAudio::m_init = FALSE;t_CKBOOL ChuckAudio::m_start = FALSE;t_CKBOOL ChuckAudio::m_go = FALSE;t_CKBOOL ChuckAudio::m_silent = FALSE;t_CKBOOL ChuckAudio::m_expand_in_mono2stereo= FALSE;t_CKUINT ChuckAudio::m_num_channels_out = NUM_CHANNELS_DEFAULT;t_CKUINT ChuckAudio::m_num_channels_in = NUM_CHANNELS_DEFAULT;t_CKUINT ChuckAudio::m_num_channels_max = NUM_CHANNELS_DEFAULT;t_CKUINT ChuckAudio::m_sample_rate = SAMPLE_RATE_DEFAULT;t_CKUINT ChuckAudio::m_buffer_size = BUFFER_SIZE_DEFAULT;t_CKUINT ChuckAudio::m_num_buffers = NUM_BUFFERS_DEFAULT;SAMPLE * ChuckAudio::m_buffer_out = NULL;SAMPLE * ChuckAudio::m_buffer_in = NULL;SAMPLE * ChuckAudio::m_extern_in = NULL;SAMPLE * ChuckAudio::m_extern_out = NULL;t_CKUINT ChuckAudio::m_dac_n = 0;t_CKUINT ChuckAudio::m_adc_n = 0;std::string ChuckAudio::m_dac_name = "";std::string ChuckAudio::m_adc_name = "";RtAudio * ChuckAudio::m_rtaudio = NULL;f_audio_cb ChuckAudio::m_audio_cb = NULL;void * ChuckAudio::m_cb_user_data = NULL;  static RtAudio::Api driverNameToApi(char const *driver){    RtAudio::Api api = RtAudio::UNSPECIFIED;    if(driver)    {    #if defined(__WINDOWS_ASIO__)        if(!strcmp(driver, "ASIO") || !strcmp(driver, "asio") || !strcmp(driver, "Asio"))            api = RtAudio::WINDOWS_ASIO;        else    #endif    #if defined(__WINDOWS_DS__)        if(!strcmp(driver, "DS") || !strcmp(driver, "ds") || !strcmp(driver, "Ds"))            api = RtAudio::WINDOWS_DS;    #endif    #if defined(__WINDOWS_WASAPI__)        if(!strcmp(driver, "WASAPI") || !strcmp(driver, "wasapi") || !strcmp(driver, "Wasapi"))            api = RtAudio::WINDOWS_WASAPI;    #endif    #if defined(__LINUX_ALSA__)        if(!strcmp(driver, "ALSA") || !strcmp(driver, "alsa") || !strcmp(driver, "Alsa")) // should match apiToDriverName            api = RtAudio::LINUX_ALSA;    #endif    #if defined(__LINUX_PULSE__)        if(!strcmp(driver, "Pulse") || !strcmp(driver, "pulse") || !strcmp(driver, "PULSE"))            api = RtAudio:: LINUX_PULSE;    #endif    #if defined(__UNIX_JACK__)        if(!strcmp(driver, "Jack") || !strcmp(driver, "jack") || !strcmp(driver, "JACK"))            api = RtAudio:: UNIX_JACK;    #endif        // XXX: add swap between ALSA, PULSE, OSS? and JACK        if(api == RtAudio::UNSPECIFIED)         {            EM_error2( 0, "unsupported audio driver: %s", driver);        }    }     // 1.5.0.0 (nshaheed) If the audio driver is UNSPECIFIED then    // return a default driver. This will depend on OS and, in the    // case of linux, which drivers chuck is being compiled with.    if(api == RtAudio::UNSPECIFIED)    {    #if defined(__PLATFORM_WIN32__)        // traditional chuck default behavior:        // DIRECT SOUND is most general albeit high-latency        api = RtAudio::WINDOWS_DS;    #elif defined(__PLATFORM_LINUX__) && defined(__LINUX_PULSE__)        api = RtAudio::LINUX_PULSE;    #elif defined(__PLATFORM_LINUX__) && defined(__LINUX_ALSA__)        api = RtAudio::LINUX_ALSA;    #elif defined(__PLATFORM_LINUX__) && defined(__UNIX_JACK__)        api = RtAudio::UNIX_JACK;    #endif    }    return api;}    //-----------------------------------------------------------------------------// name: apiToDriverName()// desc: get driver name from API//-----------------------------------------------------------------------------static char const * apiToDriverName( RtAudio::Api api ){    static char const * drivers[] = {        "system default",        "ALSA",        "Pulse",        "OSS",        "Jack",        "CoreAudio",        "WASAPI",        "ASIO",        "DS", // DirectSound        "DUMMY",        "invalid"    };     return drivers[(int)api];}    //-----------------------------------------------------------------------------// name: print()// desc: print info for an audio device//-----------------------------------------------------------------------------void print( const RtAudio::DeviceInfo & info ){    EM_error2b( 0, "device name = \"%s\"", info.name.c_str() );    if (!info.probed)        EM_error2b( 0, "probe [failed] ..." );    else    {        EM_error2b( 0, "probe [success] ..." );        EM_error2b( 0, "# output channels = %d", info.outputChannels );        EM_error2b( 0, "# input channels  = %d", info.inputChannels );        EM_error2b( 0, "# duplex Channels = %d", info.duplexChannels );        if( info.isDefaultOutput ) EM_error2b( 0, "default output = YES" );        else EM_error2b( 0, "default output = NO" );        if( info.isDefaultInput ) EM_error2b( 0, "default input = YES" );        else EM_error2b( 0, "default input = NO" );        if( info.nativeFormats == 0 ) EM_error2b( 0, "no natively supported data formats(?)!" );        else        {            EM_error2b( 0,  "natively supported data formats:" );            if( info.nativeFormats & RTAUDIO_SINT8 )   EM_error2b( 0, "   8-bit int" );            if( info.nativeFormats & RTAUDIO_SINT16 )  EM_error2b( 0, "  16-bit int" );            if( info.nativeFormats & RTAUDIO_SINT24 )  EM_error2b( 0, "  24-bit int" );            if( info.nativeFormats & RTAUDIO_SINT32 )  EM_error2b( 0, "  32-bit int" );            if( info.nativeFormats & RTAUDIO_FLOAT32 ) EM_error2b( 0, "  32-bit float" );            if( info.nativeFormats & RTAUDIO_FLOAT64 ) EM_error2b( 0, "  64-bit float" );        }        if ( info.sampleRates.size() < 1 ) EM_error2b( 0,"no supported sample rates found!" );        else        {            EM_error2b( 0, "supported sample rates:" );            for( unsigned int j = 0; j < info.sampleRates.size(); j++ )                EM_error2b( 0, "  %d Hz", info.sampleRates[j] );        }    }} /* this is the RtAudio error handler --- */static void rtAudioErrorHandler(    RtAudioErrorType t,    const std::string &errorText){    // problem finding audio devices, most likely    EM_error2b( 0, "%s", errorText.c_str() );}  //-----------------------------------------------------------------------------// name: probe()// desc: ...//-----------------------------------------------------------------------------void ChuckAudio::probe( char const * driver ){    RtAudio::Api api = driverNameToApi( driver ); // handles driver=NULL case    char const * dnm = apiToDriverName( api );    // rtaduio pointer    RtAudio * audio = NULL;    // device info struct    RtAudio::DeviceInfo info;        // allocate RtAudio    audio = new RtAudio( api, rtAudioErrorHandler );    if( !audio )    {        // error reported by our errorHandler        return;    }     // get count    int devices = audio->getDeviceCount();    EM_error2b( 0, "[%s] driver found %d audio device(s)...", dnm, devices );    EM_error2( 0, "" );     // reset -- what does this do    EM_reset_msg();        // loop over devices    for( int i = 0; i < devices; i++ )    {        info = audio->getDeviceInfo(i);        if (!info.probed) { // errorHandle reports issues above            EM_error2(0, "");            EM_reset_msg();            continue;        }                // print        EM_error2b( 0, "------( audio device: %d )---------------", i+1 );        print( info );        // skip        if( i < devices ) EM_error2( 0, "" );                // reset        EM_reset_msg();    }     // done    SAFE_DELETE( audio );     return;}    //-----------------------------------------------------------------------------// name: device_named()// desc: get device number by name; needs_dac/adc prompts further checks on//       requested device having > 0 channels//-----------------------------------------------------------------------------t_CKINT ChuckAudio::device_named( char const * driver,                                  const std::string & name,                                  t_CKBOOL needs_dac,                                  t_CKBOOL needs_adc ){    // rtaudio pointer    RtAudio * audio = NULL;    // device info struct    RtAudio::DeviceInfo info;    RtAudio::Api api = driverNameToApi(driver); // handles driver=NULL case    // char const * dnm = apiToDriverName(api);        // allocate RtAudio    audio = new RtAudio(api, rtAudioErrorHandler);    if(!audio)        return -1; // reporting in errorHandler        // get count        int devices = audio->getDeviceCount();    int device_no = -1;        // loop    for( int i = 0; i < devices; i++ )    {        // get info        info = audio->getDeviceInfo(i);        if(!info.probed)        {            // reportError handles problem            break;        }         // compare name        if( info.name.compare(name) == 0 )        {            // found!            device_no = i+1;            break;        }    }        // not found, yet    if( device_no == -1 )    {        // no exact match found; try partial match        for( int i = 0; i < devices; i++ )        {            info = audio->getDeviceInfo(i);            if(!info.probed)            {                // errorHandler reports issues                break;            }                        if( info.name.find(name) != std::string::npos )            {                // skip over ones with 0 channels, if needed                if( (needs_dac && info.outputChannels == 0) ||                    (needs_adc && info.inputChannels == 0) )                    continue;                // found                device_no = i+1;                break;            }        }    }     // clean up    SAFE_DELETE( audio );        // done    return device_no;}    //-----------------------------------------------------------------------------// name: get_current_time()// desc: ...//-----------------------------------------------------------------------------static t_CKFLOAT get_current_time( t_CKBOOL fresh = TRUE ){#ifdef __PLATFORM_WIN32__    struct _timeb t;    _ftime(&t);    return t.time + t.millitm/1000.0;#else    static struct timeval t;    if( fresh ) gettimeofday(&t,NULL);    return t.tv_sec + (t_CKFLOAT)t.tv_usec/1000000;#endif}    // watch dog globalsstatic CHUCK_THREAD g_tid_synthesis = 0;static XThread * g_watchdog_thread = NULL;static t_CKBOOL g_watchdog_state = FALSE;static t_CKFLOAT g_watchdog_time = 0;    //-----------------------------------------------------------------------------// name: watch_dog()// desc: this sniff out possible non-time advancing infinite loops//-----------------------------------------------------------------------------#if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)static void * watch_dog( void * )#elsestatic unsigned int __stdcall watch_dog( void * )#endif{    // time    t_CKFLOAT time = 0;     // boost priority?    t_CKUINT priority = XThreadUtil::our_priority;     // log    EM_log( CK_LOG_SEVERE, "starting real-time watch dog process..." );    // push log    EM_pushlog();    EM_log( CK_LOG_INFO, "watchdog timeout: %f::second", g_watchdog_timeout );    EM_log( CK_LOG_INFO, "watchdog thread priority: %d", priority );    EM_log( CK_LOG_INFO, "watchdog countermeasure priority: %d", g_watchdog_countermeasure_priority );    // pop log    EM_poplog();     // boost watchdog by same priority    if( XThreadUtil::our_priority != 0x7fffffff )        XThreadUtil::set_priority( priority );     // while going    while( g_do_watchdog )    {        // get        time = get_current_time( TRUE );        // CK_FPRINTF_STDERR( "last: %f now: %f\n", g_watchdog_time, time );         // resting        if( g_watchdog_state == FALSE )        {            // check time vs timeout            if( time - g_watchdog_time > g_watchdog_timeout )            {                // log                EM_log( CK_LOG_SEVERE, "real-time watchdog counter-measure activating..." );                // lowering priority                if( g_tid_synthesis && XThreadUtil::our_priority != 0x7fffffff )                    XThreadUtil::set_priority( g_tid_synthesis, g_watchdog_countermeasure_priority );                // set state                g_watchdog_state = TRUE;            }        }        else        {            // check time vs timeout            if( time - g_watchdog_time < g_watchdog_timeout )            {                // log                EM_log( CK_LOG_SEVERE, "real-time watchdog resting..." );                // raise priority                if( g_tid_synthesis && XThreadUtil::our_priority != 0x7fffffff )                    XThreadUtil::set_priority( g_tid_synthesis, XThreadUtil::our_priority );                // set state                g_watchdog_state = FALSE;            }        }                // advance time        usleep( 40000 );    }        // log    EM_log( CK_LOG_SEVERE, "stopping real-time watch dog process..." );     return 0;}    //-----------------------------------------------------------------------------// name: watchdog_start()// desc: start watchdog on separate thread//-----------------------------------------------------------------------------t_CKBOOL ChuckAudio::watchdog_start(){    // already    if( g_watchdog_thread )        return FALSE;     // flag    g_do_watchdog = TRUE;

Lines 1–500 of 1163.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t