portaudiodevicedriver.cpp

来自「一个语言识别引擎」· C++ 代码 · 共 327 行

CPP
327
字号
// -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*-

/*
 * Copyright (C) 2006 Paul Fitzpatrick
 * CopyPolicy: Released under the terms of the GNU GPL v2.0.
 *
 */

#include <yarp/PortAudioDeviceDriver.h>

#include <stdio.h>
#include <stdlib.h>
#include <portaudio.h>

#include <yarp/os/Time.h>

#define SAMPLE_RATE  (44100)
#define NUM_CHANNELS    (2)
#define DITHER_FLAG     (0)

#define NUM_SECONDS	0.1

//#define	NUM_SAMPLES	((int)(SAMPLE_RATE*NUM_SECONDS))
#define	NUM_SAMPLES	((int)(512))

//char 		devname[] = "/dev/dsp";

using namespace yarp::os;
using namespace yarp::dev;


// portaudio version 1.8 doesn't have Pa_ReadStream :-(

/* Select sample format. */
#if 0
#define PA_SAMPLE_TYPE  paFloat32
typedef float SAMPLE;
#define SAMPLE_SILENCE  (0.0f)
#elif 1
#define PA_SAMPLE_TYPE  paInt16
typedef short SAMPLE;
#define SAMPLE_SILENCE  (0)
#elif 1
#define PA_SAMPLE_TYPE  paInt8
typedef char SAMPLE;
#define SAMPLE_SILENCE  (0)
#else
#define PA_SAMPLE_TYPE  paUInt8
typedef unsigned char SAMPLE;
#define SAMPLE_SILENCE  (128)
#define SAMPLE_UNSIGNED
#endif

//static SAMPLE	pa_pulsecode[ NUM_SAMPLES*NUM_CHANNELS];
static double pa_tap_test = 1e6;

PortAudioDeviceDriver::PortAudioDeviceDriver() {
    system_resource = NULL;
    num_samples = 0;
    num_channels = 0;
    canRead = canWrite = false;
    loopBack = false;
    set_freq = 0;
}

PortAudioDeviceDriver::~PortAudioDeviceDriver() {
    close();
}


bool PortAudioDeviceDriver::open(PortAudioDeviceDriverSettings& config) {
    int rate = config.rate;
    int samples = config.samples;
    int channels = config.channels;
    bool wantRead = config.wantRead;
    bool wantWrite = config.wantWrite;
    if (rate==0)    rate = SAMPLE_RATE;
    if (samples==0) samples = NUM_SAMPLES;
    num_samples = samples;
    if (channels==0) channels = NUM_CHANNELS;
    num_channels = channels;
    set_freq = rate;

    buffer.allocate(num_samples*num_channels*sizeof(SAMPLE));

    // just for testing, ssssh it is a secret
    pa_tap_test = 1e6; //config.check("tap",Value(1e6)).asDouble();

    PaStreamParameters inputParameters, outputParameters;
    PaStream *stream;
    PaError    err;

    err = Pa_Initialize();
    if( err != paNoError ) {
        printf("portaudio system failed to initialize\n");
        return false;
    }

    inputParameters.device = Pa_GetDefaultInputDevice();
    inputParameters.channelCount = num_channels;
    inputParameters.sampleFormat = PA_SAMPLE_TYPE;
    if ((Pa_GetDeviceInfo( inputParameters.device ))!=0) {
        inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
    }
    inputParameters.hostApiSpecificStreamInfo = NULL;

    outputParameters.device = Pa_GetDefaultInputDevice();
    outputParameters.channelCount = num_channels;
    outputParameters.sampleFormat = PA_SAMPLE_TYPE;
    //outputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
    outputParameters.hostApiSpecificStreamInfo = NULL;


    err = Pa_OpenStream(
                        &stream,
                        wantRead?(&inputParameters):NULL,
                        wantWrite?(&outputParameters):NULL,
                        rate,
                        num_samples,
                        paClipOff,
                        NULL,
                        NULL
                        );
    if( err != paNoError ) {
        printf("portaudio stream failed to initialize, check settings\n");
        return false;
    }

    err = Pa_StartStream( stream );
    if( err != paNoError ) {
        printf("portaudio stream failed to start, check settings\n");
        return false;
    }
    printf("Reading/Writing audio data using portaudio...\n"); fflush(stdout);
    printf("   Audio parameters:\n");
    printf("     read %d, write %d loopback %d\n", wantRead, wantWrite,
           loopBack);
    printf("     (sampling) rate (in Hertz) %d\n", rate);
    printf("     samples (per block) %d\n", num_samples);
    printf("     channels %d\n", num_channels);
    config.rate = rate;
    config.samples = samples;
    config.channels = channels;
    system_resource = stream;
    canRead = wantRead;
    canWrite = wantWrite;

    return true;
}


bool PortAudioDeviceDriver::open(yarp::os::Searchable& config) {
    PortAudioDeviceDriverSettings config2;
    config2.rate = config.check("rate",Value(0)).asInt();
    config2.samples = config.check("samples",Value(0)).asInt();
    config2.channels = config.check("channels",Value(0)).asInt();
    config2.wantRead = (bool)config.check("read");
    config2.wantWrite = (bool)config.check("write");
    if (!(config2.wantRead||config2.wantWrite)) {
        config2.wantRead = config2.wantWrite = true;
    }
    if (config.check("loopback")) {
        loopBack = true;
    }
    delayed = false;
    delayedConfig = config2;
    if (config.check("delay")) {
        printf("Delaying audio configuration\n");
        delayed = true;
        return true;
    } else {
        return open(delayedConfig);
    }
}

bool PortAudioDeviceDriver::close(void) {
    PaError    err;
    if (system_resource!=NULL) {
        err = Pa_CloseStream( (PaStream*)system_resource );
        if( err != paNoError ) {
            printf("Audio error -- portaudio close failed (%s)\n",
                   Pa_GetErrorText(err));
            exit(1);
        }
        system_resource = NULL;
    }

    return true;
}

bool PortAudioDeviceDriver::getSound(yarp::sig::Sound& sound) {

    checkDelay(sound);
    
    if (!canRead) {
        Time::delay(0.25);
        return false;
    }

	// main loop to capture the waveform audio data	
    sound.resize(num_samples,num_channels);
    sound.setFrequency(set_freq);
    PaError err;
    SAMPLE *pa_pulsecode = (SAMPLE *)buffer.get();
    err = Pa_ReadStream((PaStream*)system_resource,(void*)pa_pulsecode,
                        num_samples);
    if (err == paInputOverflowed) {
        printf("Audio warning -- there was an input overflow (%s)\n",
               Pa_GetErrorText(err));
    } else if( err != paNoError ) {
        printf("Audio error -- portaudio read failed (%s)\n",
               Pa_GetErrorText(err));
        exit(1);
    }

    int idx = 0;
    for (int i=0; i<num_samples; i++) {
        for (int j=0; j<num_channels; j++) {
            sound.set(pa_pulsecode[idx],i,j);
            idx++;
        }
    }

    if (canWrite&&loopBack) {
        renderSound(sound);
    }
    return true;
}

void PortAudioDeviceDriver::checkDelay(yarp::sig::Sound& sound) {
    int _rate = sound.getFrequency();
    int _samples = sound.getSamples();    
    int _channels = sound.getChannels();
    if (!delayed) {
        if ((_rate!=0&&delayedConfig.rate!=_rate)||
            (_samples!=0&&delayedConfig.samples!=_samples)||
            (_samples!=0&&delayedConfig.channels!=_channels)) {
            printf("audio configuration mismatch, resetting\n");
            if (delayedConfig.rate!=_rate) {
                printf("  (sample rate of %d versus %d)\n",
                       delayedConfig.rate,_rate);
            }
            if (delayedConfig.rate!=_rate) {
                printf("  (sample count of %d versus %d)\n",
                       delayedConfig.samples,_samples);
            }
            if (delayedConfig.channels!=_channels) {
                printf("  (channel count of %d versus %d)\n",
                       delayedConfig.channels,_channels);
            }
            close();
            delayed = true;
        }
    }
    if (delayed) {
        delayedConfig.rate = _rate;
        delayedConfig.samples = _samples;
        delayedConfig.channels = _channels;
        printf("rate from sound is %d\n", delayedConfig.rate);
        printf("samples from sound is %d\n", delayedConfig.samples);
        printf("channels from sound is %d\n", delayedConfig.channels);
        open(delayedConfig);
        delayed = false;
    }
}


bool PortAudioDeviceDriver::renderSound(yarp::sig::Sound& sound) {
    if (sound.getSamples()==0) {
        return canWrite;
    }

    checkDelay(sound);

    if (!canWrite) {
        return false;
    }

    PaError err;
    SAMPLE *pa_pulsecode = (SAMPLE *)buffer.get();

    int idx = 0;
    for (int i=0; i<num_samples; i++) {
        for (int j=0; j<num_channels; j++) {
            pa_pulsecode[idx] = sound.get(i,j);
            idx++;
        }
    }

    err = Pa_WriteStream((PaStream*)system_resource,(void*)pa_pulsecode,
                         num_samples);
    if( err != paNoError ) {
        printf("Audio error -- portaudio write failed (%s)\n",
               Pa_GetErrorText(err));
        exit(1);
    }
    return true;
}




//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

/*
  PortAudioRender::PortAudioRender() {
  }

  PortAudioRender::~PortAudioRender() {
  close();
  }

  bool PortAudioRender::open(yarp::os::Searchable& config) {
  }

  bool PortAudioRender::close() {
  }


  bool PortAudioRender::renderSound(yarp::sig::Sound& sound) {
  }

*/

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?