I want to make a guitar effects program so I'm trying to run the example code pa_fuzz.c from PORTAUDIO API.
It works on paWDMKS host api. But when I connect the guitar using Behringer ucg 102 (for no lantency) the host api changes to paMME and I get errorCode 1 and message: "undefined external error".
Also in the visual studio output console I get tons of messages like:
'ConsoleApplication4.exe' (Win32): Unloaded 'C:\Windows\SysWOW64\SHCore.dll'
'ConsoleApplication4.exe' (Win32): Unloaded 'C:\Windows\SysWOW64\shlwapi.dll'
'ConsoleApplication4.exe' (Win32): Unloaded 'C:\Windows\SysWOW64\shell32.dll'
'ConsoleApplication4.exe' (Win32): Unloaded 'C:\Windows\SysWOW64\dbgcore.dll'
'ConsoleApplication4.exe' (Win32): Unloaded 'C:\Program Files\Native Instruments\Rig Kontrol 3 Driver\asio\rig3asio32.dll'
Here is the code snippet for the "PaHostErrorInfo" object;
PaHostErrorInfo *err2 = Pa_GetLastHostErrorInfo();
printf(err2->errorText);
Here is the source code:
#include <stdio.h>
#include <math.h>
#include "portaudio.h"
/*
** Note that many of the older ISA sound cards on PCs do NOT support
** full duplex audio (simultaneous record and playback).
** And some only support full duplex at lower sample rates.
*/
#define SAMPLE_RATE (8000)
#define PA_SAMPLE_TYPE paFloat32
#define FRAMES_PER_BUFFER (64)
typedef float SAMPLE;
float CubicAmplifier( float input );
static int fuzzCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData );
/* Non-linear amplifier with soft distortion curve. */
float CubicAmplifier( float input )
{
float output, temp;
if( input < 0.0 )
{
temp = input + 1.0f;
output = (temp * temp * temp) - 1.0f;
}
else
{
temp = input - 1.0f;
output = (temp * temp * temp) + 1.0f;
}
return output;
}
#define FUZZ(x) CubicAmplifier(CubicAmplifier(CubicAmplifier(CubicAmplifier(x))))
static int gNumNoInputs = 0;
/* This routine will be called by the PortAudio engine when audio is needed.
** It may be called at interrupt level on some machines so don't do anything
** that could mess up the system like calling malloc() or free().
*/
static int fuzzCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
SAMPLE *out = (SAMPLE*)outputBuffer;
const SAMPLE *in = (const SAMPLE*)inputBuffer;
unsigned int i;
(void) timeInfo; /* Prevent unused variable warnings. */
(void) statusFlags;
(void) userData;
if( inputBuffer == NULL )
{
for( i=0; i<framesPerBuffer; i++ )
{
*out++ = 0; /* left - silent */
*out++ = 0; /* right - silent */
}
gNumNoInputs += 1;
}
else
{
for( i=0; i<framesPerBuffer; i++ )
{
*out++ = FUZZ(*in++); /* left - distorted */
*out++ = *in++; /* right - clean */
}
}
return paContinue;
}
/*******************************************************************/
int main(void);
int main(void)
{
PaStreamParameters inputParameters, outputParameters;
PaStream *stream;
PaError err;
PaDeviceInfo *info;
err = Pa_Initialize();
if( err != paNoError ) goto error;
info = Pa_GetDeviceInfo(1);
inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
if (inputParameters.device == paNoDevice) {
fprintf(stderr,"Error: No default input device.\n");
goto error;
}
inputParameters.channelCount = 2; /* stereo input */
inputParameters.sampleFormat = PA_SAMPLE_TYPE;
inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
inputParameters.hostApiSpecificStreamInfo = NULL;
info = Pa_GetDeviceInfo(4);
outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
if (outputParameters.device == paNoDevice) {
fprintf(stderr,"Error: No default output device.\n");
goto error;
}
outputParameters.channelCount = 2; /* stereo output */
outputParameters.sampleFormat = PA_SAMPLE_TYPE;
outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
outputParameters.hostApiSpecificStreamInfo = NULL;
err = Pa_OpenStream(
&stream,
&inputParameters,
&outputParameters,
SAMPLE_RATE,
FRAMES_PER_BUFFER,
0, /* paClipOff, */ /* we won't output out of range samples so don't bother clipping them */
fuzzCallback,
NULL );
PaHostErrorInfo *err2 = Pa_GetLastHostErrorInfo();
printf(err2->errorText);
if( err != paNoError ) goto error;
err = Pa_StartStream( stream );
if( err != paNoError ) goto error;
printf("Hit ENTER to stop program.\n");
getchar();
err = Pa_CloseStream( stream );
if( err != paNoError ) goto error;
printf("Finished. gNumNoInputs = %d\n", gNumNoInputs );
Pa_Terminate();
return 0;
error:
Pa_Terminate();
fprintf( stderr, "An error occured while using the portaudio stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
return -1;
}
Can you guys please have a look on what can be the problem? I have installed BEHRINGER USB WDM AUDIO 2.8.40 drivers. (I use this usb interface with guitar rig)
I switched to another usb port and it worked. I think it's a bug from portaudio. I will leave this answer here. Now I have another problem. LATENCY :( is so frustrating to play guitar with latency.
What can be the cause of this latency? I'm connecting my guitar with behringer ucg102 (famous for no latency). And again, I use it with Guitar Rig where I have close to 0 latency. Is it a problem from portaudio library? This code is from their example "pa_fuzz.c"
New Edit: latency problem fixed by selecting the required input and output deivice.
Related
I have piano-like application, and when I'm pressing piano key, it plays a sound. In my app I wrote my own sine wave generator. App is wrote in Qt. I think that problem is with portAudio, but I can't find any solution for this.
I've recorded for you how my problem sounds: https://vocaroo.com/i/s1yiWjaJffTU
And here is my generator class:
soundEngine.h
#ifndef SOUNDENGINE_H
#define SOUNDENGINE_H
#include <QThread>
#include <math.h>
#include "portaudio.h"
#define SAMPLE_RATE (44100)
#define FRAMES_PER_BUFFER (64)
#define FREQUENCY 220
#ifndef M_PI
#define M_PI (3.14159265)
#endif
#define TABLE_SIZE (200)
typedef struct
{
float sine[TABLE_SIZE];
int phase;
}
paTestData;
class SoundEngine : public QThread
{
Q_OBJECT
public:
bool turnOFF;
void run();
static int patestCallback( const void *inputBuffer, void *outputBuffer,unsigned long framesPerBuffer,const PaStreamCallbackTimeInfo* timeInfo,PaStreamCallbackFlags statusFlags,void *userData );
void generateSine();
void removeSine();
private:
paTestData data;
PaStream *stream;
PaError err;
bool isPressed;
};
#endif // SOUNDENGINE_H
soundEngine.cpp
#include "soundengine.h"
#include <QDebug>
void SoundEngine::run()
{
PaStreamParameters outputParameters;
int i;
double t;
turnOFF = false;
isPressed = false;
static unsigned long n=0;
for( i=0; i<TABLE_SIZE; i++, n++ )
{
t = (double)i/(double)SAMPLE_RATE;
data.sine[i] = 0;
//data.sine[i] = 0.3*sin(2 * M_PI * FREQUENCY * t);
/*data.sine[i] *= 1.0/2;
data.sine[i] += 0.5*sin(2 * M_PI * (FREQUENCY+110) * t);
data.sine[i] *= 2.0/3;
data.sine[i] += (1.0/3)*sin(2 * M_PI * (FREQUENCY+60) * t);
data.sine[i] *= 3.0/4;
data.sine[i] += (1.0/4)*sin(2 * M_PI * (FREQUENCY+160) * t);*/
}
data.phase = 0;
err = Pa_Initialize();
if(err != paNoError) qDebug()<<"Błąd przy inicjalizacji strumienia:"<<Pa_GetErrorText(err);
outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
if (outputParameters.device == paNoDevice) qDebug()<<"Błąd: Brak domyślnego urządzenia wyjścia!";
outputParameters.channelCount = 2; /* stereo output */
outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */
outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
outputParameters.hostApiSpecificStreamInfo = NULL;
err = Pa_OpenStream(
&stream,
NULL, /* no input */
&outputParameters,
SAMPLE_RATE,
FRAMES_PER_BUFFER,
paClipOff, /*paNoFlag we won't output out of range samples so don't bother clipping them */
patestCallback,
&data );
if(err != paNoError) qDebug()<<"Błąd przy otwieraniu strumienia:"<<Pa_GetErrorText(err);
//err = Pa_StartStream( stream );
if(err != paNoError) qDebug()<<"Błąd przy starcie strumienia:"<<Pa_GetErrorText(err);
while (turnOFF == false) {
Pa_Sleep(500);
}
//err = Pa_StopStream( stream );
if(err != paNoError) qDebug()<<"Błąd przy zatrzymywaniu strumienia:"<<Pa_GetErrorText(err);
err = Pa_CloseStream( stream );
if(err != paNoError) qDebug()<<"Błąd przy zamykaniu strumienia:"<<Pa_GetErrorText(err);
Pa_Terminate();
}
int SoundEngine::patestCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
{
paTestData *callData = (paTestData*)userData;
float *out = (float*)outputBuffer;
float sample;
unsigned long i;
(void) timeInfo; /* Prevent unused variable warnings. */
(void) statusFlags;
(void) inputBuffer;
for( i=0; i<framesPerBuffer; i++ )
{
sample = callData->sine[callData->phase++];
*out++ = sample; /* left */
*out++ = sample; /* right */
if( callData->phase >= TABLE_SIZE ) callData->phase -= TABLE_SIZE;
}
return paContinue;
}
void SoundEngine::generateSine()
{
if(isPressed == false)
{
for(int i=0; i<TABLE_SIZE; i++)
{
data.sine[i] += 0.3*sin(2 * M_PI * 440 * ((double)i/(double)SAMPLE_RATE));
}
isPressed = true;
err = Pa_StartStream( stream );
}
}
void SoundEngine::removeSine()
{
err = Pa_StopStream( stream );
for(int i=0; i<TABLE_SIZE; i++)
{
data.sine[i] -= 0.3*sin(2 * M_PI * 440 * ((double)i/(double)SAMPLE_RATE));
}
isPressed = false;
}
When I'm pressing button, function
void SoundEngine::generateSine()
is running - it generates sound. When I release the button, method
void SoundEngine::removeSine()
removes the sound.
MODERATOR ATTENTION: This question seems to belong more to dsp.stackexchange than this forum.
There's nothing wrong with either your sound or PortAudio. The sound you're hearing at the end is just the result of the audio being abruptly stopped. Take a look at the following image of a sound that has a constant amplitude through the entire duration. This sound will have an audible pop at the end.
Conversely, if we attenuate the amplitude by modifying the waveform's envelope (the same sound as in image #1) so that it resembles the sound in image #2, we won't hear any abrupt change(s) in the sound at the end.
In conclusion, if your goal is to completely eliminate the pops that you're hearing, fade out (or fade in) your sound(s).
I am struggling with outputting user selected audio tones with portaudio. I have based a function on the paex_sine.cpp and modified it somewhat based on this post multi-audio-tones-to-sound-card-using-portaudio
I am able to generate a sine wave on the fly by placing the sin(n * FREQ * 2 * PI / SAMPLE_RATE) calculation in paCallBackMethod() but the frequency isn't correct, and doesn't change based on user input.
Here is my function code.
void CDeepWaveDlg::generateSound(float freq)
{
pitch = tone;
offset = freq;
class Sine
{
public:
Sine() : stream(0), left_phase(0), right_phase(0)
{
}
bool open(PaDeviceIndex index)
{
PaStreamParameters outputParameters;
outputParameters.device = index;
if (outputParameters.device == paNoDevice) {
return false;
}
outputParameters.channelCount = 2; /* stereo output */
outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */
outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency;
outputParameters.hostApiSpecificStreamInfo = NULL;
PaError err = Pa_OpenStream(
&stream,
NULL, /* no input */
&outputParameters,
SAMPLE_RATE,
FRAMES_PER_BUFFER,
paClipOff, /* we won't output out of range samples so don't bother clipping them */
&Sine::paCallback,
this /* Using 'this' for userData so we can cast to Sine* in paCallback method */
);
if (err != paNoError)
{
/* Failed to open stream to device !!! */
return false;
}
err = Pa_SetStreamFinishedCallback(stream, &Sine::paStreamFinished);
if (err != paNoError)
{
Pa_CloseStream(stream);
stream = 0;
return false;
}
return true;
}
bool close()
{
if (stream == 0)
return false;
PaError err = Pa_CloseStream(stream);
stream = 0;
return (err == paNoError);
}
bool start()
{
if (stream == 0)
return false;
PaError err = Pa_StartStream(stream);
return (err == paNoError);
}
bool stop()
{
if (stream == 0)
return false;
PaError err = Pa_StopStream(stream);
return (err == paNoError);
}
private:
/* The instance callback, where we have access to every method/variable in object of class Sine */
int paCallbackMethod(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags)
{
float *out = (float*)outputBuffer;
unsigned long i;
(void)timeInfo; /* Prevent unused variable warnings. */
(void)statusFlags;
(void)inputBuffer;
for (i = 0; i<framesPerBuffer; i++)
{
float v = sin(i * pitch * 2.0 * M_PI /(float)SAMPLE_RATE);
float v2 = sin(i * (pitch + (float)offset) * 2.0 * M_PI /(float)SAMPLE_RATE);
*out++ = v;
*out++ = v2;
}
return paContinue;
}
/* This routine will be called by the PortAudio engine when audio is needed.
** It may called at interrupt level on some machines so don't do anything
** that could mess up the system like calling malloc() or free().
*/
static int paCallback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData)
{
/* Here we cast userData to Sine* type so we can call the instance method paCallbackMethod, we can do that since
we called Pa_OpenStream with 'this' for userData */
return ((Sine*)userData)->paCallbackMethod(inputBuffer, outputBuffer,
framesPerBuffer,
timeInfo,
statusFlags);
}
void paStreamFinishedMethod()
{
printf("Stream Completed: %s\n", message);
}
/*
* This routine is called by portaudio when playback is done.
*/
static void paStreamFinished(void* userData)
{
return ((Sine*)userData)->paStreamFinishedMethod();
}
PaStream *stream;
float sine[TABLE_SIZE];
int left_phase;
int right_phase;
char message[20];
};
PaError err;
Sine sine;
err = Pa_Initialize();
if (err != paNoError) goto error;
if (sine.open(Pa_GetDefaultOutputDevice()))
{
if (sine.start())
{
Pa_Sleep(NUM_SECONDS * 1000);
sine.stop();
}
sine.close();
}
Pa_Terminate();
The only way I am able to get close to the desired pitch is to increase frames per buffer, which is currently 64, but I still run into the problem of not changing frequency based on user selection.
This problem is definitely beyond my skill level, but I am hoping someone can help me understand what's going on here.Thanks in advance for any help.
I want to use PortAudio in Game Maker by using a DLL.
I made the callback function in C++ and used that to calculate the frequency of the incoming sample stream. In the DLL I made a few export functions: one that initiates the stream, one that closes the stream and one that gets the frequency variable generated by the callback.
Now when I called the PortAudioStart() function in Game Maker, the game shut down without any warning/error/message of any kind. I put MessageBox()'es in between the lines of code, to check what was the source of the crash. It showed the first, second and third ones, and then it crashed, not even showing the error MessageBox. So it turned out that Pa_StartStream() caused it.
Now I wonder: why does this crash occur, and how can I fix it?
Note: I tested this DLL by letting a C++ program call it, and in that case it worked totally as planned.
I am using GM8.0 and NetBeans 7.3 with the gcc compiler from Cygwin 4.
The start and end functions (leaving out all includes and definitions of global variables):
#define GMEXPORT extern "C" __declspec (dllexport)
GMEXPORT double __cdecl PortAudioStart() {
err = Pa_Initialize();
if( err != paNoError ) goto error;
MessageBoxA(NULL, "1", "PortAudio DLL", MB_ICONINFORMATION);
inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
if (inputParameters.device == paNoDevice) {
goto error;
}
inputParameters.channelCount = 1; /* mono input */
inputParameters.sampleFormat = PA_SAMPLE_TYPE;
inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
inputParameters.hostApiSpecificStreamInfo = NULL;
MessageBoxA(NULL, "2", "PortAudio DLL", MB_ICONINFORMATION);
err = Pa_OpenStream(
&stream,
&inputParameters,
NULL, //&outputParameters
SAMPLE_RATE,
FRAMES_PER_BUFFER,
0,
PaCallback,
NULL );
if( err != paNoError ) goto error;
MessageBoxA(NULL, "3", "PortAudio DLL", MB_ICONINFORMATION);
err = Pa_StartStream( stream );
if( err != paNoError ) goto error;
MessageBoxA(NULL, "4", "PortAudio DLL", MB_ICONINFORMATION);
return 1;
error:
MessageBoxA(NULL, "Apparently it doesn't work!", "PortAudio DLL", MB_ICONINFORMATION);
Pa_Terminate();
return 0;
}
GMEXPORT double __cdecl PortAudioEnd() {
err = Pa_CloseStream( stream );
if( err != paNoError ) goto error;
Pa_Terminate();
return 1;
error:
MessageBoxA(NULL, "Apparently it doesn't work!", "PortAudio DLL", MB_ICONINFORMATION);
Pa_Terminate();
return 0;
}
GMEXPORT double __cdecl getFreq()
{
if (Pa_IsStreamStopped(stream) == 0)
{
return frequency; // this variable is constantly changed in the callback function
}
else
{
return 0;
}
}
void calculateFreq(bool sign)
{
unsigned int j;
bool check;
diffsamp = maxsamp - minsamp;
if (!sign)
{
diffsampmax = max((diffsampmax*.85), (double)diffsamp);
maxsamp = 0;
}
if (sign)
{
diffsampmax = max((diffsampmax*.85), (double)diffsamp);
minsamp = 0;
}
check = ( diffsamp > max(25.0,diffsampmax*.90) );
if (sign == lastsign)
{
check = false;
}
if (check)
{
if (timepassed - peaks[0] < 500)
{
for ( j=numpeaks-1; j>0; j-- )
{
peaks[j] = peaks[j-1];
}
}
else
{
for ( j=0; j<numpeaks; j++ )
{
peaks[j] = 0;
}
}
peaks[0] = timepassed;
double diff = peaks[0]-peaks[numpeaks-1];
double peaktime = diff/(numpeaks-1)*2; //*2 because maxdiff is at +>- and ->+
frequency = 1/((double)peaktime/(double)SAMPLE_RATE);
if (peaks[numpeaks-1] <= 0 || frequency < 20) frequency = 0;
lastsign = sign;
}
}
static int PaCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
const SAMPLE *in = (const SAMPLE*)inputBuffer;
unsigned int i;
unsigned int j;
(void) timeInfo; // Prevent unused variable warnings.
(void) statusFlags;
(void) userData;
SAMPLE samp;
if( inputBuffer == NULL )
{
//nothing happens
}
else
{
for( i=0; i<framesPerBuffer; i++ )
{
timepassed += 1;
samp = *in++;
changed = false;
if (samp > 0)
{
if (!sign)
{
sign = true;
changed = true;
}
maxsamp = max(maxsamp,samp);
}
else
{
if (sign)
{
sign = false;
changed = true;
}
minsamp = min(minsamp,samp);
}
if (changed)
{
calculateFreq(sign);
}
}
}
return paContinue;
}
GML:
//// Script: pa_init()
globalvar _pa_freq,_pa_start,_pa_end;
var dll_name;
dll_name = "c:\Users\<Username>\Documents\NetBeansProjects\GMDLLtest\dist\Debug\Cygwin_4.x-Windows\libGMDLLtest.dll";
_pa_freq = external_define(dll_name, "getFreq", dll_cdecl, ty_real, 0);
_pa_start = external_define(dll_name, "PortAudioStart", dll_cdecl, ty_real, 0);
_pa_end = external_define(dll_name, "PortAudioEnd", dll_cdecl, ty_real, 0);
////--------------------------------------------------------------------------------
//// Script: pa_start()
return external_call(_pa_start);
////--------------------------------------------------------------------------------
//// Script: pa_end()
return external_call(_pa_end);
////--------------------------------------------------------------------------------
//// Script: pa_freq()
return external_call(_pa_freq);
P.S: If anything is unclear, please ask, my knowledge of C++ isn't really outstanding.
I'm using portaudio to play a sound. I want to be able to select the output via the UI. I managed it like that :
PaError err = Pa_Initialize();
if( err != paNoError )
return false;
qDebug() <<"Port audio succeed initialization !";
int numDevices;
numDevices = Pa_GetDeviceCount();
if( numDevices <= 0 )
{
qDebug() << "ERROR: Pa_CountDevices returned " << numDevices;
return false;
}
const PaDeviceInfo *deviceInfo;
bool isThereOutput = false;
int i = 0;
while(i < numDevices and !isThereOutput)
{
deviceInfo = Pa_GetDeviceInfo( i );
isThereOutput = (deviceInfo->maxOutputChannels > 0);
i++;
}
if(!isThereOutput)
{
qDebug() << "No output device";
return false;
}
PaError errorOpening;
if(outputDevice != "")
{
PaStreamParameters outputDeviceInfo;
int numDevices = Pa_GetDeviceCount();
const PaDeviceInfo *deviceInfo;
for(int i = 0; i<numDevices; i++ )
{
deviceInfo = Pa_GetDeviceInfo( i );
if(deviceInfo->maxOutputChannels > 0 && deviceInfo->name == outputDevice)
{
outputDeviceInfo.device = i;
outputDeviceInfo.channelCount = 1;
outputDeviceInfo.sampleFormat = paInt8;
outputDeviceInfo.suggestedLatency = deviceInfo->defaultLowOutputLatency;
}
}
if(outputDeviceInfo.channelCount > 1)
{
errorOpening = Pa_OpenStream(&stream, NULL, &outputDeviceInfo, SAMPLE_RATE, FRAME_PER_BUFFER, paNoFlag, audioCallback, this);
}
}
if(outputDevice == "" or errorOpening != paNoError)
{
if(errorOpening != paNoError)
qDebug() << "Can't open selected device ("<< outputDevice <<"), switching to the default one. Error : " << Pa_GetErrorText(errorOpening);
errorOpening = Pa_OpenDefaultStream( &stream,
0, /* no input channels */
1, /* mono output */
paInt8, /* 8 bits output */
SAMPLE_RATE,
FRAME_PER_BUFFER, /* frames per buffer, i.e. the number
of sample frames that PortAudio will
request from the callback. Many apps
may want to use
paFramesPerBufferUnspecified, which
tells PortAudio to pick the best,
possibly changing, buffer size.*/
audioCallback, /* this is your callback function */
this ); /*This is a pointer that will be passed to
your callback*/
}
if(errorOpening != paNoError)
return false;
if(Pa_StartStream( stream ) != paNoError)
return false;
And it fails :
Can't open selected device ( "Sortie intégr" ), switching to the default one. Error : Invalid error code (value greater than zero)
But I can't figure why OpenStream fails with a strange error code and Pa_OpenDefaultStream works like a charm.
So :
Why does it fails ?
Why does it throw a wrong error code ?
I assume you use C++ (though there are several curious and and or in your code.)
If your for loop didn't find any PaDeviceInfo which satisfies eviceInfo->maxOutputChannels > 0 && deviceInfo->name == outputDevice, then your outputDeviceInfo is left un-initialized. That means its channelConnect can have any values including large negative values. Then Pa_OpenStream isn't invoked and your errorOpening is also left un-initialized. I bet that's the reason of Invalid error code (value greater than zero) when you feed it into Pa_GetErrorText().
I would like to know how to know the relationship of the portaudio test examples and how to get the frequency.I was wondering how i could send a specifc frequency to sound card?
1. How to know the specific frequency of that the code send to sound card
2. How i could send sin(2*pi*f*t) and sin((2*pi*f*t)-3.14) which is a delayed version. Here is the code. Any help is highly appreciated
#include <stdio.h>
#include <math.h>
#include "portaudio.h"
#define NUM_SECONDS (20)
#define SAMPLE_RATE (44100)
#define AMPLITUDE (0.9)
#define FRAMES_PER_BUFFER (64)
#define OUTPUT_DEVICE Pa_GetDefaultOutputDeviceID()
//#define OUTPUT_DEVICE (2)
#ifndef M_PI
#define M_PI (3.14159265)
#endif
#define TABLE_SIZE (200)
typedef struct
{
float sine[TABLE_SIZE];
int left_phase;
int right_phase;
}
paTestData;
static int patestCallback( void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
PaTimestamp outTime, void *userData )
{
paTestData *data = (paTestData*)userData;
float *out = (float*)outputBuffer;
unsigned long i;
int finished = 0;
(void) outTime; /* Prevent unused variable warnings. */
(void) inputBuffer;
for( i=0; i<framesPerBuffer; i++ )
{
*out++ = data->sine[data->left_phase]; /* left */
*out++ = data->sine[data->right_phase]; /* right */
data->left_phase += 1;
if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
data->right_phase +=2.57; /* higher pitch so we can distinguish left and right. */
if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
}
return finished;
}
/*******************************************************************/
int main(void);
int main(void)
{
PortAudioStream *stream;
PaError err;
paTestData data;
int i;
printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d, devID = %d\n",
SAMPLE_RATE, FRAMES_PER_BUFFER, OUTPUT_DEVICE);
/* initialise sinusoidal wavetable */
for( i=0; i<TABLE_SIZE; i++ )
{
data.sine[i] = (float) (AMPLITUDE * sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ));
}
data.left_phase = data.right_phase = 0;
err = Pa_Initialize();
if( err != paNoError ) goto error;
err = Pa_OpenStream(
&stream,
paNoDevice,/* default input device */
0, /* no input */
paFloat32, /* 32 bit floating point input */
NULL,
OUTPUT_DEVICE,
2, /* stereo output */
paFloat32, /* 32 bit floating point output */
NULL,
SAMPLE_RATE,
FRAMES_PER_BUFFER,
0, /* number of buffers, if zero then use default minimum */
paClipOff, /* we won't output out of range samples so don't bother clipping them */
patestCallback,
&data );
if( err != paNoError ) goto error;
err = Pa_StartStream( stream );
if( err != paNoError ) goto error;
printf("Play for %d seconds.\n", NUM_SECONDS ); fflush(stdout);
Pa_Sleep( NUM_SECONDS * 1000 );
err = Pa_StopStream( stream );
if( err != paNoError ) goto error;
err = Pa_CloseStream( stream );
if( err != paNoError ) goto error;
Pa_Terminate();
printf("Test finished.\n");
return err;
error:
Pa_Terminate();
fprintf( stderr, "An error occured while using the portaudio stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
return err;
}
A quick look suggests SAMPLE_RATE / TABLE_SIZE will give you you the cycles per second for the sine wave, which appears to work out to be ~220Hz, which is an A3 note. Though from the code I can see the left channel is getting this wave and the right channel is stepping through the table at 2.75x the base rate which I guess would be about 606Hz which doesn't hit a note, I expect this sample sounds quite horrible!
To send the Sine and a delayed version you just look up the delayed version using an offset to the phase parameter, taking care to wrap around properly, and add the waves together. You'll probably want to lower the AMPLITUDE to avoid clipping.