I'm Trying to open a stream in PortAudio - c++

i'm using this api: Pa_OpenStream()
// Open line-in stream
err = Pa_OpenStream(&m_stream,
&m_inputParameters,
&m_outputParameters,
44100, // sample rate
128, // frames per buffer
0, // paClipOff
OmniLineInCallback,
NULL);
and i'm getting err = -9993, i.e. paBadIODeviceCombination.
I configured both input and output device and i want to record from the input and transmit to the output playback device.
i don't know why i'm getting this err?!
Appreciate your help,
Aviel

Make sure you pass correct parameters to the method. For that you may to do the following.
Initialize PortAudio via Pa_Initialize()
Check what audio devices are actually available for you through PortAudio. Use Pa_GetDeviceCount() and then Pa_GetDeviceInfo() for each available device. Look how many inputs and outputs are actually available for each device, and don't pass a quantity greater than it supports.
Fill the corresponding fields of the PaStreamParameters struct with the correct values.
This is how I open my ASIO/CoreAudio device (I also use Qt framework, but this does not affect the meaning of the example).
How I init the library and find the device I need:
int MyClass::initSoundInterfaces()
{
int result = -1; // target ASIO/CoreAudio device index
PaError err = Pa_Initialize();
const PaDeviceInfo* deviceInfo;
int numDevices = Pa_GetDeviceCount();
for( int DevIndex=0; DevIndex<numDevices; DevIndex++ )
{
deviceInfo = Pa_GetDeviceInfo( DevIndex );
QString str = Pa_GetHostApiInfo(deviceInfo->hostApi)->name;
qDebug() << "DEV: ApiInfo: " << str;
qDebug() << "defaultSampleRate = " << deviceInfo->defaultSampleRate;
qDebug() << "maxInputChannels = " << deviceInfo->maxInputChannels;
qDebug() << "maxOutputChannels = " << deviceInfo->maxOutputChannels;
QRegExp reg_exp(".*(ASIO|Core.*Audio).*", Qt::CaseInsensitive);
if( str.contains(reg_exp) )
{
if(deviceInfo->maxInputChannels > 0
&& deviceInfo->maxOutputChannels > 1)
{
result = DevIndex;
break;
}
}
}
return result;
}
Then I pass the given device index to the following method to open and start a stream:
bool MyClass::startAudio(int DevIndex)
{
PaError err = paNoError;
PaStreamParameters in_param;
in_param.device = DevIndex;
g_ChannelCount = min(Pa_GetDeviceInfo(DevIndex)->maxInputChannels,
MAX_INPUT_COUNT);
in_param.channelCount = g_ChannelCount;
in_param.hostApiSpecificStreamInfo = NULL;
in_param.sampleFormat = paFloat32 | paNonInterleaved;
in_param.suggestedLatency = 0;
// Pa_GetDeviceInfo(DevIndex)->defaultLowInputLatency;
PaStreamParameters out_param;
out_param.device = DevIndex;
out_param.channelCount = 2; // I do not need more than 2 output channels
out_param.hostApiSpecificStreamInfo = NULL;
out_param.sampleFormat = paFloat32 | paNonInterleaved; // Not all devices support 32 bits
out_param.suggestedLatency = 0;
// Pa_GetDeviceInfo(DevIndex)->defaultLowOutputLatency;
if(err == paNoError)
{
err = Pa_OpenStream(&stream,
&in_param,
&out_param,
nSampleRate,
cBufferSize/*paFramesPerBufferUnspecified*/,
paNoFlag,
process,
0);
}
err = Pa_StartStream(stream);
...
}

OK, when call Pa_GetDeviceCount() i get many available devices.
currently i have the onborad sound card and a usb sound card. (each of them have input and output devices)
when i configure input and output of the OnBoard sound card it works fine.
but when i configure input of the usb card and output of the onboard card it returns err = paInvalidDevice.
also i saw that each card has several devices that differs in hostApi (paInDevelopment=0, paDirectSound=1, paMME=2)
what is the diffeence between them? and which device should i choose? it's ok to mix between them, i.e. choose input device that have "paDirectSound" and output that have "paInDevelopment"?
another thing that i paid attention to is the sample rate and number of channels, is it ok to have input with sample rate of 44100 and output of 48000?
and one last thing: you confiugured the variables: nSampleRate nBufferSize according to what?
thanks,
aviel.

it is because the host api type of input device and output device are not same. For example:
import sounddevice as sd
sd.query_devices()
will get the available devices:
> 1 ADAT (7+8) (RME Fireface UC), MME (2 in, 0 out)
2 SPDIF/ADAT (1+2) (RME Fireface , MME (2 in, 0 out)
3 Analog (1+2) (RME Fireface UC), MME (2 in, 0 out)
...
14 扬声器 (RME Fireface UC), MME (0 in, 8 out)
...
44 ASIO Fireface USB, ASIO (18 in, 18 out)
where I have delete the unconcerned devices. here we can see:
device 3 is an input device with host api MME,
device 14 is an output device with host api MME,
device 44 is an io device with host api ASIO.
Now if you want call the sounddevice.playrec() method, you must make sure the io devices you choose has the same kind of api, for example:
import sounddevice as sd
sd.playrec(data, device=(3, 14)) # OK
sd.playrec(data, device=(44, 44)) # OK
sd.playrec(data, device=(3, 44)) # bad
sd.playrec(data, device=(44, 14)) # bad

Related

ESP32 i2s_read returns empty buffer after calling this function

I am trying to record audio from an INMP441 which is connected to a ESP32 but returning the buffer containing the bytes the microphone read always leads to something which is NULL.
The code for setting up i2s and the microphone is this:
// i2s config
const i2s_config_t i2s_config = {
.mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX), // receive
.sample_rate = SAMPLE_RATE, // 44100 (44,1KHz)
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, // 32 bits per sample
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // use right channel
.communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // interrupt level 1
.dma_buf_count = 64, // number of buffers
.dma_buf_len = SAMPLES_PER_BUFFER}; // 512
// pin config
const i2s_pin_config_t pin_config = {
.bck_io_num = gpio_sck, // serial clock, sck (gpio 33)
.ws_io_num = gpio_ws, // word select, ws (gpio 32)
.data_out_num = I2S_PIN_NO_CHANGE, // only used for speakers
.data_in_num = gpio_sd // serial data, sd (gpio 34)
};
// config i2s driver and pins
// fct must be called before any read/write
esp_err_t err = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
if (err != ESP_OK)
{
Serial.printf("Failed installing the driver: %d\n", err);
}
err = i2s_set_pin(I2S_PORT, &pin_config);
if (err != ESP_OK)
{
Serial.printf("Failed setting pin: %d\n", err);
}
Serial.println("I2S driver installed! :-)");
Setting up the i2s stuff is no problem at all. The tricky part for me is reading from the i2s:
// 44KHz * Byte per sample * time in seconds = total size in bytes
const size_t recordSize = (SAMPLE_RATE * I2S_BITS_PER_SAMPLE_32BIT / 8) * recordTime; //recordTime = 5s
// size in bytes
size_t totalReadSize = 0;
// 32 bits per sample set in config * 1024 samples per buffers = total bits per buffer
char *samples = (char *)calloc(totalBitsPerBuffer, sizeof(char));
// number of bytes read
size_t bytesRead;
Serial.println("Start recording...");
// read until wanted size is reached
while (totalReadSize < recordSize)
{
// read to buffer
esp_err_t err = i2s_read(I2S_PORT, (void *)samples, totalBitsPerBuffer, &bytesRead, portMAX_DELAY);
// check if error occurd, if so stop recording
if (err != ESP_OK)
{
Serial.println("Error while recording!");
break;
}
// check if bytes read works → yes
/*
for (int i = 0; i < bytesRead; i++)
{
uint8_t sample = (uint8_t) samples[i];
Serial.print(sample);
} */
// add read size to total read size
totalReadSize += bytesRead;
// Serial.printf("Currently recorded %d%% \n", totalReadSize * 100 / recordSize);
}
// convert bytes to mb
double_t totalReadSizeMB = (double_t)totalReadSize / 1e+6;
Serial.printf("Total read size: %fMb\n", totalReadSizeMB);
Serial.println("Samples deref");
Serial.println(*samples);
Serial.println("Samples");
Serial.println(samples);
return samples;
Using this code leads to the following output:
I2S driver installed! :-)
Start recording...
Total read size: 0.884736Mb
Samples deref
␀
Samples
When I uncomment the part where I iterate over the bytes read part I get something like this:
200224231255255224210022418725525522493000902552550238002241392542552241520020425225508050021624525501286700194120022461104022421711102242271030018010402242510000188970224141930022291022410185022487830021679001127500967200666902241776600246610224895902244757022418353002224802242274302249741022419339009435001223102242432602243322022412120001241402245911022418580084402248325525522461252255044249255224312452552242212372552241272352550342302552241212262552242112212550252216255014621325501682092550112205255224161202255224237198255224235194255224231922552248518725501141832550421812552241951762550144172255018168255034164255224173157255018215525522455152255028148255021014425505214025522487137255014613225522412112825502361252550180120255018011725522451172550252113255224133111255061082550248105255224891042552249910125522439972550138942552242279225503287255224101832552242478125522410178255224231732552244970255224336525501766225501426125502325625522424553255224109492550186[...]
This shows that the microphone is able to record, but I cant return the actual value of the buffer.
While programming this code I looked up at the official doku and some code which seems to work elsewhere.
I am also new to C++ and am not used to work with pointers.
Does anyone know what the problem could be?

MT166-С connection not responding. С++ Library

I have a MT166-C dispenser. I am writing C ++ code to manage a dispenser.
In development use SDK (attach the link) and I have a problem.
To work with the dispenser, I open the COM port. Code:
int input_port;
string com_str = "\\\\.\\COM";
std::cin >> input_port;
std::cout << "\nInput COM value: " << input_port << std::endl;
com_str = com_str + to_string(input_port);
char* cstr = &com_str[0];
char* port_com = cstr;
HANDLE port = CommOpenWithBaut(port_com, 9600);
if (port == 0)
{
std::cout << "Cannot open connect!\n\n" << std::endl;
return -1;
}
After I use the HANDLE port to call methods.
int iRetn = 0;
BYTE byStatus = 0;
string str = "";
iRetn = MT166_GetStatus(hPortHandle, 0x98, byStatus);
Similar to documentation (p. 3.1 in MT166-C.docx - Link Too)
DLLEXPORT int APIENTRY MT166_GetStatus(HANDLE hComHandle, BYTE CardNum,BYTE &byStatus)
///Parameter:
// hComHandle: Input parameter, serial port handle, obtained by opening the serial port
// CarderNum: Input parameter, card dispenser NO. Default is 0x98
// byStatus: output parameter, card dispenser status word
//Return value:
//Succeed, return value is 0
//failed, return value is not 0 = -1 no communication
In response, I get the code -1 - no communication. For other methods, the situation is the same.
I do not understand why there is no answer from the dispenser (no communication). I would be very grateful for any help.
I use connections via rs232 cable or USB adapter rs232 - without change.
Thank you for your time.
First of all, you need to check the physical availability of an external device.
Check baud speed, data bits, stop bits, row control parameters...
Check the OS hardware list for driver correctness.

ALSA - samplerate conversion

I have a text-to-speech application, that generate an audio-stream (raw-data) with a samplerate of 22kHz.
I have a USB-SoundCard that support only 44kHz.
With my asound.conf I can play wav-files that contains 22kHz and 44kHz audio-stream without problems in aplay.
My Application use the alsa-libs and set the samplerate of the device.
In this case only 44kHz will succeed, because the hardware supports only this samplerate. But now, when i write the generated audio-stream to alsa, it sounds wrong, because the samplerates dosn't match. The audio-stream (raw-data) dosn't contain any header information, so I think alsa don't use any plugin zu convert the samplerate. Alsa don't know that the stream has a different samplerate
My question is now, what is the right way to tell alsa, that the generated audio-stream have a different samplerate, so the alsa-plugin convert it.
The following code works on the USB SoundCard only with sampleRate = 44100, otherwise an error occured (-22, invalid parameters).
void initAlsa()
{
const char* name = "default";
alsaAudio = true;
writeRiffAtClose = false;
int err = snd_pcm_open (&alsaPlaybackHandle, name, SND_PCM_STREAM_PLAYBACK, 0);
if (err < 0)
throw TtsException({"Alsa: cannot open playback audio device ", name, " (" , snd_strerror (err), ")"}, 0);
sampleRate = 44100;
err = snd_pcm_set_params(alsaPlaybackHandle, // pcm PCM handle
SND_PCM_FORMAT_S16_LE, // format required PCM format
SND_PCM_ACCESS_RW_INTERLEAVED, // access required PCM access
2, // channels required PCM channels (Stereo)
sampleRate, // rate required sample rate in Hz
1, // soft_resample 0 = disallow alsa-lib resample stream, 1 = allow resampling
250000); /* 0.25sec */ // latency required overall latency in us
if (err < 0)
throw TtsException({"Alsa: cannot set parameters (" , err, " = " , snd_strerror(err), ") on ", name}, 0);
LOG_DEBUG("Alsa audio initialized");
}
Other way are, I manuelly convert the sample rate, before i put it to alsa, but i think: why not use the alsa-plugin.
I don't have the option to get 44kHz audio-stream from the tts-engine (it's another software).
Or exist another way, that I don't see?
Best regards.

Unable to open UART. Ensure it is not in use by another application

There seems to be a weird problem that I have encountered while dealing with UART on the Raspberry Pi. The problem is simple, I initialize the UART as shown here and set the baud rate at 9600 and even the transmission of first few bytes goes on well. However, after sometime when I continuously keep sending the data, the RPi shows this message on the screen: Unable to open UART. Ensure it is not in use by another application.
I don't know where am I going wrong and make to things more complicated, I encountered this problem a couple of days ago before which, the code ran just fine without errors for long period of time.
Here is the code snippet:
minMaxLoc( diffImg, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );
xpos=maxLoc.x;
ypos=maxLoc.y;
xposs = xpos - xposp;
yposs = ypos - yposp;
xposp = xpos;
yposp = ypos;
char x_tx_buffer[20], y_tx_buffer[20];
char x_dummy_buffer[20];
char y_dummy_buffer[20];
char *p_x_tx_buffer, *p_y_tx_buffer;
sprintf(x_dummy_buffer,"%d", (int)(abs(xposs*2.5)));
sprintf(y_dummy_buffer,"%d", (int)(abs(yposs*2.5)));
p_x_tx_buffer = &x_tx_buffer[0];
*p_x_tx_buffer++ = x_dummy_buffer[0];
*p_x_tx_buffer++ = x_dummy_buffer[1];
*p_x_tx_buffer++ = x_dummy_buffer[2];
*p_x_tx_buffer++ = x_dummy_buffer[3];
p_y_tx_buffer = &y_tx_buffer[0];
*p_y_tx_buffer++ = y_dummy_buffer[0];
*p_y_tx_buffer++ = y_dummy_buffer[1];
*p_y_tx_buffer++ = y_dummy_buffer[2];
*p_y_tx_buffer++ = y_dummy_buffer[3];
uart0_filestream = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY); //Open in non blocking read/write mode
if (uart0_filestream == -1)
{
//ERROR - CAN'T OPEN SERIAL PORT
printf("Error - Unable to open UART. Ensure it is not in use by another application\n");
}
if (uart0_filestream != -1)
{
int countx = write(uart0_filestream, &x_tx_buffer[0], (p_x_tx_buffer - &x_tx_buffer[0])); //Filestream, bytes to write, number of bytes to write
int county = write(uart0_filestream, &y_tx_buffer[0], (p_y_tx_buffer - &y_tx_buffer[0])); //Filestream, bytes to write, number of bytes to write
if (countx < 0 || county < 0)
{
printf("UART TX error\n");
}
}
Where am I going wrong?
You need to do this at the end of the routine.
close(uart0_filestream);

Problems capturing audio from the second sound card

I have written a program that captures sound via waveInOpen() in Wuindows. It works great on the michrophone-device on the main-board, but when I try to capture from the second sound-card, I get only [static] noise. Recording with SoundRecorder works great on both cards. Does any1 know if there are any known problems with waveInOpen() and multiple input-devices?
The code that opens the input-device looks like this:
void Audio::OpenDevice(const int device,
const Audio::SamplingRate samplingRate)
throw (Exception, std::exception)
{
switch(samplingRate)
{
...
case AUDIO_16BIT_44KHZ_STEREO:
bits_per_sample_ = 16;
hertz_ = 44100;
channels_ = 2;
break;
...
default:
throw Exception("Audio::OpenDevice(): Invalid enum value");
}
// Open the device
const UINT_PTR dev = (-1 == device) ? (UINT_PTR)WAVE_MAPPER : (UINT_PTR)device;
WAVEFORMATEX wf = {0};
wf.wFormatTag = WAVE_FORMAT_PCM;
wf.nChannels = channels_;
wf.wBitsPerSample = bits_per_sample_;
wf.nSamplesPerSec = hertz_;
wf.nBlockAlign = wf.nChannels * wf.wBitsPerSample / 8;
`
const MMRESULT result = waveInOpen(&hwi_, dev, &wf,
(DWORD_PTR)OnWaveEvent, (DWORD_PTR)this, CALLBACK_FUNCTION);
if (MMSYSERR_NOERROR != result)
throw Exception("waveInOpen()");
std::cout << "Audio: Sampling at " << hertz_ << " hertz from "
<< channels_ << " channel(s) with " << bits_per_sample_
<< " bits per sample. "
<< std::endl;
}
Did you check the microphone gain settings, mixer settings, that the microphone hardware you're using is compatible with the input you have it hooked to, etc? Hooking most microphones to a line in connection does not work well. The microphone doesn't have enough output voltage to drive that kind of input.
My guess (purely a guess) is that the bit depth or sample rate is somehow incorrect. If you are using 16/44100, then I would assume it is supported (pretty common). But maybe the sound card is not set for those rates. I have an external Edirol sound card that I have to physically turn on and off when I change bit depth (and adjust a separate switch on it).