int main(int argc, char *argv[])
{
QCoreApplication b(argc, argv);
QBuffer *buffer;
QAudioOutput *a;
QAudioFormat format;
format.setSampleRate(8000);
format.setChannelCount(1);
format.setSampleSize(8);
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::UnSignedInt);
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
if (info.isFormatSupported(format))
{
cout << "Format supported" << endl;
}
else
{
cout << "Format not supported" << endl;
}
char *data = (char*)malloc(32768 * sizeof(char));
//generating a sound
for (int i = 0; i<256; ++i)
{
for (int j = 0; j<128; ++j)
{
data[i * 128 + j] = (char)j;
}
}
cout << "Created samples" << endl;
//copying into the buffer
buffer = new QBuffer;
buffer->open(QIODevice::ReadWrite);
buffer->seek(0);
buffer->write(data, 32768);
cout << "Filled buffer" << endl;
//playing
QThread thr;
a = new QAudioOutput(format);
//a->moveToThread(&thr);
//thr.start();
//QMetaObject::invokeMethod(a, "start", Q_ARG(QIODevice*, buffer));
a->start(buffer);
system("pause");
return b.exec();
}
I am trying to make my console application output sound and I can't figure out why my QAudioOutput object doesn't do that. I placed the code above. Can you tell me what did I do wrong?
P.S. If i write that vector to a file and play it as raw sound I can hear a low frequency buzz.
First, you definitely shouldn't have system("pause") before your main loop as #Hayt mentioned.
Second, you should seek to the beginning after you've written the data.
buffer->write(data, 32768);
buffer->seek(0);
Related
The question says it all. I am going in circles here. I set snd_pcm_sw_params_set_stop_threshold to boundary (and zero too just for fun) and I am still getting buffer underrun errors on snd_pcm_writei. I cannot understand why. The documentation is pretty clear on this:
If the stop threshold is equal to boundary (also software parameter - sw_param) then automatic stop will be disabled
Here is a minimally reproducible example:
#include <alsa/asoundlib.h>
#include <iostream>
#define AUDIO_DEV "default"
#define AC_FRAME_SIZE 960
#define AC_SAMPLE_RATE 48000
#define AC_CHANNELS 2
//BUILD g++ -o main main.cpp -lasound
using namespace std;
int main() {
int err;
unsigned int i;
snd_pcm_t *handle;
snd_pcm_sframes_t frames;
snd_pcm_uframes_t boundary;
snd_pcm_sw_params_t *sw;
snd_pcm_hw_params_t *params;
unsigned int s_rate;
unsigned int buffer_time;
snd_pcm_uframes_t f_size;
unsigned char buffer[AC_FRAME_SIZE * 2];
int rc;
for (i = 0; i < sizeof(buffer); i++)
buffer[i] = random() & 0xff;
if ((err = snd_pcm_open(&handle, AUDIO_DEV, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
cout << "open error " << snd_strerror(err) << endl;
return 0;
}
s_rate = AC_SAMPLE_RATE;
f_size = AC_FRAME_SIZE;
buffer_time = 2500;
cout << s_rate << " " << f_size << endl;
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_hw_params_any(handle, params);
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(handle, params, AC_CHANNELS);
snd_pcm_hw_params_set_rate_near(handle, params, &s_rate, 0);
snd_pcm_hw_params_set_period_size_near(handle, params, &f_size, 0);
cout << s_rate << " " << f_size << endl;
rc = snd_pcm_hw_params(handle, params);
if (rc < 0) {
cout << "open error " << snd_strerror(err) << endl;
return 0;
}
snd_pcm_sw_params_alloca(&sw);
snd_pcm_sw_params_current(handle, sw);
snd_pcm_sw_params_get_boundary(sw, &boundary);
snd_pcm_sw_params_set_stop_threshold(handle, sw, boundary);
rc = snd_pcm_sw_params(handle, sw);
if (rc < 0) {
cout << "open error " << snd_strerror(err) << endl;
return 0;
}
snd_pcm_sw_params_current(handle, sw);
snd_pcm_sw_params_get_stop_threshold(sw, &boundary);
cout << "VALUE " << boundary << endl;
for (i = 0; i < 1600; i++) {
usleep(100 * 1000);
frames = snd_pcm_writei(handle, buffer, f_size);
if (frames < 0)
frames = snd_pcm_recover(handle, frames, 0);
if (frames < 0) {
cout << "open error " << snd_strerror(frames) << endl;
break;
}
}
return 0;
}
Okay I figured it out. To anyone who runs into this issue who also has pipewire or pulse (or any other thirdparty non-alsa audio card) enabled as the "default" card the solution is to not use pipewire or pulse directly. It seems that snd_pcm_sw_params_set_stop_threshold is not implemented properly in pipewire/pulseaudio. You'll notice that if you disable pipewire or pulse this code will run exactly the way you want it to run.
Here is how you can disable pulseaudio (which was the issue on my system):
systemctl --user stop pulseaudio.socket
systemctl --user stop pulseaudio.service
Although a much better solution is to just set the AUDIO_DEV to write directly to an alsa card. You can find the names of these cards by running aplay -L. But in 95% of cases updating AUDIO_DEV in my sample code to the following:
#define AUDIO_DEV "hw:0,0"
Will usually fix the issue.
I'm trying to encalpsulate alsa inside a class.
The problem is when i try to use :
snd_pcm_hw_params_get_period_size(this->__params, &period_size, NULL);
or
snd_pcm_hw_params_get_period_time(this->__params, &time_period, NULL);
inside void alsa_control::record_to_file(std::string filename, int duration_in_us);
in the cpp it send 0 in period and seems to be unmodified for period_time
The .h
#ifndef ALSA_RECORDING_H
#define ALSA_RECORDING_H
#include <iostream>
#include <alsa/asoundlib.h>
#include <wav_functions.h>
#define STEREO 2
#define MONO 1
using std::cout;
using std::endl;
class alsa_control {
public:
void record_to_file(std::string filename, int duration_in_us);
alsa_control(unsigned int rate, unsigned long frames, int bits, unsigned int stereo_mode);
~alsa_control();
private:
unsigned int __rate;
unsigned int __stereo_mode;
int __bits;
snd_pcm_uframes_t __frames;
snd_pcm_hw_params_t *__params;
snd_pcm_t *__handle;
void open_pcm_device();
void set_parameters_ALSA();
alsa_control()=delete;
alsa_control(const alsa_control&)=delete;
};
#endif /* ALSA_RECORDING_H */
and the .cpp
#include <alsa_control.h>
alsa_control::alsa_control(unsigned int rate, unsigned long frames, int bits, unsigned int stereo_mode)
: __rate(rate),
__stereo_mode(stereo_mode),
__bits(bits),
__frames(frames) {
this->open_pcm_device();
snd_pcm_hw_params_alloca(&this->__params);
this->set_parameters_ALSA();
}
alsa_control::~alsa_control() {
snd_pcm_drain(this->__handle);
snd_pcm_close(this->__handle);
}
void alsa_control::open_pcm_device() {
int rc = snd_pcm_open(&this->__handle, "default", SND_PCM_STREAM_CAPTURE, 0);
if (rc < 0) {
cout << "ERROR : unable to open pcm device: " << snd_strerror(rc) << endl;
exit(1);
}
}
void alsa_control::set_parameters_ALSA() {
snd_pcm_hw_params_any(this->__handle, this->__params); // def values
snd_pcm_hw_params_set_access(this->__handle, this->__params, SND_PCM_ACCESS_RW_NONINTERLEAVED); //non interleaved
snd_pcm_hw_params_set_format(this->__handle, this->__params, SND_PCM_FORMAT_S16_LE); //16bits little-endian
snd_pcm_hw_params_set_channels(this->__handle, this->__params, this->__stereo_mode); // stereo ou mono
snd_pcm_hw_params_set_rate_near(this->__handle, this->__params, &this->__rate, NULL); // sample rate (freq echantillonage)
auto ret = snd_pcm_hw_params_set_period_size_near(this->__handle, this->__params, &this->__frames, NULL); //frames pour une période
int rc = snd_pcm_hw_params(this->__handle, this->__params);
if (rc < 0) {
cout << "ERROR - unable to set hw parameters: " << snd_strerror(rc) << endl;
exit(1);
}
}
void alsa_control::record_to_file(std::string filename, int duration_in_us) {
std::ofstream f;
int rc;
int nb_ech = 0;
snd_pcm_uframes_t period_size;
unsigned int time_period;
filename += ".wav";
f.open(filename, std::ios::binary);
write_header_wav(f, this->__rate, (short) this->__bits, (short) this->__stereo_mode, 10000); //10000 is a constant because we don't know the size of the recording
snd_pcm_hw_params_get_period_size(this->__params, &period_size, NULL);
period_size = 2048;
snd_pcm_uframes_t size = period_size * 2; /* 2 bytes/sample, 1 channels */
char *buffer = (char *) malloc(size);
snd_pcm_hw_params_get_period_time(this->__params, &time_period, NULL);
time_period = 128000;
long loops = duration_in_us / time_period;
while (loops-- > 0) {
rc = (int) snd_pcm_readi(this->__handle, buffer, period_size);
if (rc == -EPIPE) {
cout << "ERROR - overrun occurred" << endl;
snd_pcm_prepare(this->__handle);
} else if (rc < 0) {
cout << "ERROR - error from read: " << snd_strerror(rc) << endl;
} else if (rc != (int) period_size) {
cout << "ERROR - short read, read " << rc << " frames" << endl;
}
if (!(loops % 10))cout << loops << endl;
f.write(buffer, rc * 2);
nb_ech += rc;
}
f.close();
f.open(filename, std::ios::binary | std::ios::in);
write_header_wav(f, this->__rate, (short) this->__bits, (short) this->__stereo_mode, nb_ech);
f.close();
free(buffer);
}
I've just figured one way to make it works. But i'm always wondering why the functions don't works correctly.
snd_pcm_hw_params_get_period_size(this->_params, period_size, NULL); and snd_pcm_hw_params_get_period_time(this->_params, time_period, NULL); works fine when inside the set_parameters_ALSA method.
Then i've just added them to my class as private members :
snd_pcm_uframes_t _period_size; and unsigned int _time_period;
And changed the two functions to :
void alsa_control::set_parameters_ALSA() {
snd_pcm_hw_params_any(this->_handle, this->_params); // def values
snd_pcm_hw_params_set_access(this->_handle, this->_params, SND_PCM_ACCESS_RW_NONINTERLEAVED); //non interleaved
snd_pcm_hw_params_set_format(this->_handle, this->_params, SND_PCM_FORMAT_S16_LE); //16bits little-endian
snd_pcm_hw_params_set_channels(this->_handle, this->_params, this->_stereo_mode); // stereo ou mono
snd_pcm_hw_params_set_rate_near(this->_handle, this->_params, &this->_rate, NULL); // sample rate (freq echantillonage)
snd_pcm_hw_params_set_period_size_near(this->_handle, this->_params, &this->_frames, NULL); //frames pour une période
int rc = snd_pcm_hw_params(this->_handle, this->_params);
if (rc < 0) {
cout << "ERROR - unable to set hw parameters: " << snd_strerror(rc) << endl;
exit(1);
}
snd_pcm_hw_params_get_period_size(this->_params, &this->_period_size, NULL);
snd_pcm_hw_params_get_period_time(this->_params, &this->_time_period, NULL);
}
and
void alsa_control::record_to_file(std::string filename, int duration_in_us) {
std::ofstream f;
int rc;
int nb_ech = 0;
filename += ".wav";
f.open(filename, std::ios::binary);
write_header_wav(f, this->_rate, (short) this->_bits, (short) this->_stereo_mode, 10000); //10000 is an arbitrary constant because we don't know the size of the recording
snd_pcm_uframes_t size = this->_period_size * 2; /* 2 bytes/sample, 1 channels */
char *buffer = (char *) malloc(size);
long loops = duration_in_us / this->_time_period;
while (loops-- > 0) {
rc = (int) snd_pcm_readi(this->_handle, buffer, this->_period_size);
if (rc == -EPIPE) {
cout << "ERROR - overrun occurred" << endl;
snd_pcm_prepare(this->_handle);
} else if (rc < 0) {
cout << "ERROR - error from read: " << snd_strerror(rc) << endl;
} else if (rc != (int) this->_period_size) {
cout << "ERROR - short read, read " << rc << " frames" << endl;
}
f.write(buffer, rc * 2);
nb_ech += rc;
}
f.close();
f.open(filename, std::ios::binary | std::ios::in);
write_header_wav(f, this->_rate, (short) this->_bits, (short) this->_stereo_mode, nb_ech);
f.close();
free(buffer);
}
EDIT :
This problem seems to be related to driver.
Using : Advanced Linux Sound Architecture Driver Version k3.16.0-31-generic don't work with the question version
Using : Advanced Linux Sound Architecture Driver Version k3.18.8+ works good
Currently I've written a program (in Visual Studio C++) based on the available example code of "libsndfile" in which I've just added a subtraction-function to subtract one (channel of a) WAV-file with another.
The program worked perfectly for files with a limit of 4 channels.
The problem is that as soon as I upload a file with as many as 5 channels or more, the program refuses to execute the function. This is independent of the frame-size as I've managed to process 4-channel files which were many times larger than some 5/6-channel-files which I have used.
Has anyone encountered this or a similar problem before? If requested I will provide the source code.
My apologies for the bad structure, I don't really optimize until I get the whole deal working.
Code:
#include <sndfile.hh>
#include <tinyxml2.h>
#include <iostream>
#include <fstream>
#define BLOCK_SIZE 32
using TiXmlDocument = tinyxml2::XMLDocument;
using CStdStringA = std::string;
int main(int argc, char* argv[])
{
SNDFILE *infile = NULL;
SNDFILE *infile2 = NULL;
SNDFILE *outfile = NULL;
SF_INFO sfinfo;
SF_INFO sfinfo2;
SF_INFO sfinfoOut;
sf_count_t readcount;
//int filetype = SF_FORMAT_WAV | SF_FORMAT_PCM_24; // 24-bit Wav-Files
TiXmlDocument iDoc; // Init tinyXML
int i; // Iteration-var;
short BufferIn[BLOCK_SIZE]; // Buffer1
short BufferIn2[BLOCK_SIZE]; // Buffer2
short BufferOut[BLOCK_SIZE];
CStdStringA FileLoc, FileName, FileLocWav, FileLocTxt,FileLocRaw; // OutputFile locationstring
CStdStringA WavName, WavName2, FileIn, FileIn2;
FileLoc = "C:\\Testfiles\\";
//TextTitle(FileLoc); // Print console-header
printf("Name Wavefile 1:\n");
std::cin >> WavName;
FileIn = FileLoc + WavName + ".wav";
if((infile = sf_open(FileIn.c_str(),SFM_READ,&sfinfo)) == NULL) // Open Wav-file 2 instance
{
printf("Not able to open input file 1\n");
printf("\n\nPress any key to exit."); // Exit-text if file not present
puts(sf_strerror(NULL)) ;
return 1;
}
std::cout << "Wav file 1 succesfully opened." << std::endl;
std::cout << "\nChannels: " << sfinfo.channels << "\nFrames: " << sfinfo.frames << std::endl; // Print Channels & Frames
std::cout << "Samplerate: " << sfinfo.samplerate << "\n\n" << std::endl;// Print Samplerate
printf("Name Wavefile 2:\n");
std::cin >> WavName2;
FileIn2 = FileLoc + WavName2 + ".wav";
if((infile2 = sf_open(FileIn2.c_str(),SFM_READ,&sfinfo2)) == NULL) // Open Wav-file 2 instance
{
printf("Not able to open input file 2\n");
printf("\n\nPress any key to exit."); // Exit-text if file not present
puts(sf_strerror(NULL)) ;
return 1;
}
std::cout << "Wav file 2 succesfully opened." << std::endl;
std::cout << "\nChannels: " << sfinfo2.channels << "\nFrames: " << sfinfo2.frames << std::endl; // Print Channels & Frames
std::cout << "Samplerate: " << sfinfo2.samplerate << "\n\n" << std::endl;// Print Samplerate
//{
//std::cout << "Format differs from eachother, abort program.";
//printf("\n\nPress any key to exit."); // Exit-text
//return 1;
//}
if(sfinfo.channels != sfinfo2.channels) // Abort if channels not the same
{
std::cout << "Channelammount differs from eachother, abort program.";
printf("\n\nPress any key to exit."); // Exit-text
return 1;
}
if(sfinfo.samplerate != sfinfo2.samplerate) // Abort if samplerate not the same
{
std::cout << "Samplerate differs from eachother, abort program.";
printf("\n\nPress any key to exit."); // Exit-text
return 1;
}
std::cout << "Give a filename for Txt- & Wav-file: ";
std::cin >> FileName;
FileLoc += FileName; // Fuse Filelocation with given name
FileLocTxt = FileLoc + ".txt";
FileLocWav = FileLoc + ".wav";
FileLocRaw = FileLoc + "Raw.txt";
sfinfoOut.channels = sfinfo.channels;
sfinfoOut.format = sfinfo.format;
sfinfoOut.samplerate = sfinfo.samplerate;
if((outfile = sf_open(FileLocWav.c_str(),SFM_WRITE,&sfinfoOut)) == NULL) // Open Wav-file 2 instance
{
printf("Not able to create output file \n");
printf("\n\nPress any key to exit."); // Exit-text if file not present
puts(sf_strerror(NULL)) ;
return 1;
}
std::ofstream myfile;
myfile.open(FileLocTxt.c_str(),std::ios::app);
std::ofstream myfileRaw;
myfileRaw.open(FileLocRaw.c_str(),std::ios::app);
while((readcount = sf_read_short(infile, BufferIn, BLOCK_SIZE))) // While there are still frames to be processed
{
//process_data (data, readcount, sfinfo.channels) ;
auto readcount2 = sf_read_short(infile2, BufferIn2, BLOCK_SIZE);
for(i = 0; i < BLOCK_SIZE; i++) // BLOCK_SIZE decides the chunk-size
{
BufferOut[i] = BufferIn[i] - BufferIn2[i];
myfileRaw << BufferOut[i];
}
sf_write_short(outfile, BufferOut, BLOCK_SIZE) ; // Write the data to a new file
}
sf_close(infile); // Close Wav-file handlers
sf_close(infile2);
sf_close(outfile);
myfile.close(); // Close text-file handlers
printf("\n\nPress any key to exit."); // Exit-text
return 0;
}
The documentation states:
File Read Functions (Items)
sf_count_t sf_read_short (SNDFILE *sndfile, short *ptr, sf_count_t items) ;
sf_count_t sf_read_int (SNDFILE *sndfile, int *ptr, sf_count_t items) ;
sf_count_t sf_read_float (SNDFILE *sndfile, float *ptr, sf_count_t items) ;
sf_count_t sf_read_double (SNDFILE *sndfile, double *ptr, sf_count_t items) ;
The file read items functions fill the array pointed to by ptr with the requested number of items. The items parameter must be an integer product of the number of channels or an error will occur
There's your problem, since BLOCK_SIZE is a multiple of 1,2,4 but not of 3 and 5 - so that would fail.
About the problem that program completes as if calculations had taken place: add appropriate error handling.
I have written the following code below to display a video in OpenCV. I have compiled it fine but when I run it, the window that is supposed to show the video opens but it is too small to actually see if the video is playing. Everything else seems to be working fine. The width, height and number of frames are printed on the command line as coded. Anyone know what the problem is? Check it out.
void info()
{
cout << "This program will accept input video with fixed lengths and produce video textures" << endl;
}
int main(int argc, char *argv[])
{
info();
if(argc != 2)
{
cout << "Please enter more parameters" << endl;
return -1;
}
const string source = argv[1];
VideoCapture input_vid(source);
if(! input_vid.isOpened())
{
cout << "Error: Could not find input video file" << source << endl;
return -1;
}
Size S = Size((int) input_vid.get(CV_CAP_PROP_FRAME_WIDTH), //Acquire size of input video
(int) input_vid.get(CV_CAP_PROP_FRAME_HEIGHT));
cout << "Width: = " << S.width << " Height: = " << S.height << " Number of frames: " << input_vid.get(CV_CAP_PROP_FRAME_COUNT)<<endl;
const char* PLAY = "Video player";
namedWindow(PLAY, CV_WINDOW_AUTOSIZE);
//imshow(PLAY,100);
char c;
c = (char)cvWaitKey(27);
//if ( c == 27)break;
return 0;
}
assuming video is from webcam:
capture = CaptureFromCAM( 0 );
SetCaptureProperty(capture,CV_CAP_PROP_FRAME_HEIGHT, 640);
SetCaptureProperty(capture,CV_CAP_PROP_FRAME_WIDTH, 480);
this will fix your problem
another simple tweak could be using CV_WINDOW_NORMAL instead of CV_WINDOW_AUTOSIZE
namedWindow(PLAY, CV_WINDOW_AUTOSIZE);
which lets you resize the window manually
int main (int argc, char* argv[])
{
QApplication app(argc, argv);
QTextStream cout(stdout, QIODevice::WriteOnly);
// Declarations of variables
int answer = 0;
do {
// local variables to the loop:
int factArg = 0;
int fact(1);
factArg = QInputDialog::getInteger(0, "Factorial Calculator",
"Factorial of:", 1);
cout << "User entered: " << factArg << endl;
int i=2;
while (i <= factArg) {
fact = fact * i;
++i;
}
QString response = QString("The factorial of %1 is %2.\n%3")
.arg(factArg).arg(fact)
.arg("Do you want to compute another factorial?");
answer = QMessageBox::question(0, "Play again?", response,
QMessageBox::Yes | QMessageBox::No);
} while (answer == QMessageBox::Yes);
return EXIT_SUCCESS;
}
Link taken from here
originally from above link...
Can you help me out with "QInputDialog..(4th line of do while loop)" How do I get to know about which arguments does it have?
I saw the documentation but i couldnt find out, whats this "0" and "1" in arguments..
Read the docs. Basically - first is a parent widget (NULL in this case), and the 1 after label is a default value.