SDL2 - SDL_AudioSpec audio plays endlessly when not called in while loop - c++

I've made this simple program according to a github code.
All you have to take care of is the while loop at the end of the main() method.
#include "SDL2\SDL.h"
constexpr const char* WAV_PATH = "applause.wav";
#include <iostream>
static Uint8* sg_pAudioPos;
static Uint32 sg_AudioLength;
struct CWavWrapper
{
Uint32 m_Length;
Uint8* m_pBuffer;
SDL_AudioSpec m_Spec;
};
void ExitProgram(int code = 0)
{
system("pause");
exit(code);
}
void AudioCallback(void* pData, Uint8* pStream, int Length);
#undef main
int main()
{
using std::cout;
using std::cerr;
using std::endl;
if (SDL_Init(SDL_INIT_AUDIO) < 0)
{
cerr << "couldnt init audio: " << SDL_GetError() << endl;
ExitProgram(1);
}
cout << "Loading wav... " << WAV_PATH << endl;
static CWavWrapper Wav;
if(SDL_LoadWAV(WAV_PATH,&Wav.m_Spec,&Wav.m_pBuffer,&Wav.m_Length) == NULL)
{
cerr << "couldnt load wav: " << SDL_GetError() << endl;
ExitProgram(1);
}
Wav.m_Spec.callback = AudioCallback;
Wav.m_Spec.userdata = NULL;
sg_pAudioPos = Wav.m_pBuffer;
sg_AudioLength = Wav.m_Length;
cout << "Opening Audio..." << endl;
if (SDL_OpenAudio(&Wav.m_Spec, NULL) < 0)
{
cerr << "couldn't open audio: " << SDL_GetError() << endl;
ExitProgram(1);
}
cout << "Success! Starting Audio..." << endl;
SDL_PauseAudio(0);
while (sg_AudioLength > 0)
{
//If I remove this output line or as in the GitHub example not do the SDL_Delay() the wav gets played infinitely.
//how does printing out a variable change its value (as it should do only in the callback)?
cout << "sg_AudioLength: " << sg_AudioLength << endl;
}
SDL_CloseAudio();
SDL_FreeWAV(Wav.m_pBuffer);
ExitProgram(0);
}
void AudioCallback(void* pData, Uint8* pStream, int Length)
{
if (sg_AudioLength == 0)
return;
if (Length > sg_AudioLength)
{
Length = sg_AudioLength;
}
SDL_MixAudio(pStream, sg_pAudioPos, Length, SDL_MIX_MAXVOLUME);
sg_pAudioPos += Length;
sg_AudioLength -= Length;
}
As you can see at the end of the main() function, I put a description on what happens when I remove the cout line.
I think it might has to do something with the AudioCallback only being called when a certain code is done. But I am not sure and I would like to get an answer to it.
EDIT: I've noticed that when anything gets processed in the while loop, the audio seems to play right. Does anything from compiling to run time notice that the loop does not change the variable and thinks that this is now an endless loop so the loop does not even try to check the variable again?

Related

pipe() and fork() example: basic_string::M_construct null not valid

Another try with getting parallel processes to work. Please excuse the amount of code but every attempt to shorten it makes the error vanish.
What I tested so far:
sending int from parent to child, from child to parent, and from parent to child and then back: works
processing a list of int: send from parent to child, modify and back to parent: works
more data: int + string, from parent to child, modify and back to parent: works
a list of data the same way: works
But when I run the same function that works a second time it always fail.
This is the function that creates the child process:
//parent sends binary data from list to child which sends back modified data
bool processParallel6(std::vector<std::pair<int, std::string>> & data)
{
//define pipe
int parent2Child[2];
int child2Parent[2];
//create pipe
pipe(parent2Child);
pipe(child2Parent);
//fork
pid_t child = fork();
if(child == 0) //child process
{
//close not needed end of pipe
close(parent2Child[1]);
close(child2Parent[0]);
for(;;)
{
struct pollfd pfd;
pfd.fd = parent2Child[0];
pfd.events = POLLIN;
//wait until data is available at the pipe
cout << "c: poll ..." << endl;
if(poll(&pfd, 1, -1) < 0)
{
cout << "c: poll: " << strerror(errno) << endl;
exit(-1);
}
cout << "c: poll says there are data" << endl;
if((pfd.revents&POLLIN) == POLLIN)
{
int data;
std::string text;
if(!readData3(parent2Child[0], data, text))
exit(-2);
cout << "c: data received: " << data << " " << text << endl;
if(data == -1)
break;
if(!writeData3(child2Parent[1], data * 2, text + text))
exit(-3);
cout << "c: sent data to parent: " << 2 * data << " " << text + text << endl;
}
}
close(parent2Child[0]);
close(child2Parent[1]);
exit(0);
}
else //parent process
{
//close not needed end of pipe
close(parent2Child[0]);
close(child2Parent[1]);
//send data to child
if(!writeData3(parent2Child[1], data.back().first, data.back().second))
return false;
cout << "p: wrote data: " << data.back().first << " " << data.back().second << endl;
data.pop_back();
//read result from child
for(;;)
{
struct pollfd pfd;
pfd.fd = child2Parent[0];
pfd.events = POLLIN;
//wait until data is available at the pipe
cout << "p: poll ..." << endl;
if(poll(&pfd, 1, -1) < 0)
{
cout << "p poll: " << strerror(errno) << endl;
return false;
}
cout << "p: poll says there are data" << endl;
if((pfd.revents&POLLIN) == POLLIN)
{
int data;
std::string text;
if(!readData3(child2Parent[0], data, text))
return false;
cout << "p: data received: " << data << " " << text << endl;
}
if(data.empty())
break;
if(!writeData3(parent2Child[1], data.back().first, data.back().second))
return false;
cout << "p: wrote data: " << data.back().first << " " << data.back().second << endl;
data.pop_back();
}
//send stop data
if(!writeData3(parent2Child[1], -1, "notext"))
return false;
cout << "p: sent stop data " << endl;
//wait for child to end
wait(nullptr);
//close all pipes
close(parent2Child[1]);
close(child2Parent[0]);
}
return true;
}
For reading and writing data I use this two functions:
bool readData3(int fd, int & number, std::string & text)
{
char numberBuf[sizeof(int)];
int bytesRead = read(fd, numberBuf, sizeof(int));
if(bytesRead > 0)
{
number = *(int *)numberBuf;
}
else if(bytesRead < 0)
{
cout << "readData3: " << strerror(errno) << endl;
return false;
}
char sizeBuf[sizeof(int)];
int size = -1;
bytesRead = read(fd, sizeBuf, sizeof(int));
if(bytesRead > 0)
{
size = *(int *)sizeBuf;
}
else if(bytesRead < 0)
{
cout << "readData3: " << strerror(errno) << endl;
return false;
}
char textBuf[size];
bytesRead = read(fd, textBuf, size);
if(bytesRead > 0)
{
text = std::string(textBuf);
}
else if(bytesRead < 0)
{
cout << "readData3: " << strerror(errno) << endl;
return false;
}
return true;
}
bool writeData3(int fd, const int number, const std::string text)
{
int bytesWritten = write(fd, &number, sizeof(int));
if(bytesWritten < 0)
{
cout << "writeData3: " << strerror(errno) << endl;
return false;
}
int size = text.size() + 1;
bytesWritten = write(fd, &size, sizeof(int));
if(bytesWritten < 0)
{
cout << "writeData3: " << strerror(errno) << endl;
return false;
}
bytesWritten = write(fd, text.c_str(), size);
if(bytesWritten < 0)
{
cout << "writeData3: " << strerror(errno) << endl;
return false;
}
return true;
}
Finally I run it like this:
#include <iostream>
#include <vector>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <bitset>
#include <memory>
#include <poll.h>
#include <cstring>
using namespace std;
int main(int /*argc*/, char* /*argv*/[])
{
std::vector<std::pair<int, std::string>> data;
data.push_back(std::make_pair(1, "one"));
data.push_back(std::make_pair(2, "two"));
cout << "6a ########################################################" << endl << flush;
processParallel6(data);
cout << "6b ########################################################" << endl << flush;
processParallel6(data);
return 0;
}
This is the output:
6a ###############################################
p: wrote data: 2 two
p: poll ...
c: poll ...
c: poll says there are data
c: data received: 2 two
p: poll says there are data
p: data received: 4 twotwo
p: wrote data: 1 one
p: poll ...
c: sent data to parent: 4 twotwo
c: poll ...
c: poll says there are data
c: data received: 1 one
p: poll says there are data
p: data received: 2 oneone
p: sent stop data
c: sent data to parent: 2 oneone
c: poll ...
c: poll says there are data
c: data received: -1 notext
6b ###################################################
c: poll ...
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_M_construct null not valid
c: poll says there are data
c: poll ...
c: poll says there are data
c: poll ...
The last 4 lines are repeated a thousands of times. This output comes most of the times, but sometimes I have seen a std::bad_alloc error. When I try strace it crashes too, but when it runs I have seen directly after the second run of processParallel6() a line with mmap, ENOEM and 'Cannot allocate memory'
What happens here? Why is it working the first time, but not the second time?
You attempting to copy an invalid std::string reference.
std::terminate is getting called in the constructor of std::string. The constructor is implicitly called in processParallel6 when calling writeData3:
bool writeData3(int fd, const int number, const std::string text)
...
//send data to child
if(!writeData3(parent2Child[1], data.back().first, data.back().second))
return false;
You are expecting that data.back().second is a valid string reference, but nothing in the code ensures that is the case.
You construct data and place two entries in it:
data.push_back(std::make_pair(1, "one"));
data.push_back(std::make_pair(2, "two"));
In the first call to processParallel6 you run the following block of code twice:
if(!writeData3(parent2Child[1], data.back().first, data.back().second))
return false;
cout << "p: wrote data: " << data.back().first << " " << data.back().second << endl;
data.pop_back();
At this point data is empty. You cannot make another call to processParallel6 because it expects that data contains at least one element.

QT frame visualisation

Currently started to work with qt and found some bug in my code, and I can't understand where it comes from. Maybe you will see and explain why it happens.
Here is main.cpp code part which changes shutter from 3000 to maximum:
if (camera.test_cam->liveFrameReady())
{
camera.visualizeFrame(camera.test_cam->liveFrame());
camera.set_shutter(0, 1, 3000 + i * 200);
controlWidget->update(camera.test_cam->liveFrame());
i++;
}
The code works slowly(1 fps ), because of the camera.visuzlizeFrame() method:
void OsCam::visualizeFrame(Common::FrameHandle hFrame)
{
void* buffer_ptr = this->getFrameData(hFrame);
int width = hFrame->dataType()->width();
int height = hFrame->dataType()->height();
cv::Mat m(height, width, CV_8UC3, (int*)buffer_ptr);
cv::imshow("test image", m);
cv::waitKey(1);
}
Gui interface shows the camera frame in real time, test image from visualizeFrame at the background
Actionally, I don't need to call this method (I used it just to be sure that I can read the memory and I used opencv because I am more familiar with it).
But if I get rid of this camera.visuzlizeFrame() my gui becomes white and does not give any response.
Even if I use cv::waitKey or Sleep functions, nothing happens to the gui.
void ControlWidget::update(Common::FrameHandle hFrame)
{
try
{
QImage img((uchar*)hFrame->buffer()->data(), hFrame->dataType()->width(), hFrame->dataType()->height(), QImage::Format::Format_RGB888);
QSize standart_size = QSize(hFrame->dataType()->width() / 3, hFrame->dataType()->height() / 3);
QPixmap rectPxmp = QPixmap::fromImage(img).scaled(standart_size);
this->camera_1->setPixmap(rectPxmp);
this->camera_2->setPixmap(rectPxmp);
cv::waitKey(300);
}
catch (GeneralException& e)
{
std::cout << e.what() << std::endl;
}
}
Shall I go to QThreads? One thread for reading the buffer and another one for visualization of gui?
Thank you!
some additional code:
void* OsCam::getFrameData(Common::FrameHandle hFrame)
{
bool displayFrameData = false;
void* pFrameData = NULL;
try
{
if (hFrame)
{
if (displayFrameData)
{
// display information about the frame
cout << "Frame index: " << hFrame->frameIndex();
cout << "Frame timestamp: " << hFrame->timestamp();
// display information about the frame "data type"
DataTypeHandle hDataType = hFrame->dataType();
cout << "Frame size in bytes: " << hDataType->frameSizeInBytes() << endl;
cout << "Width in pixels: " << DataType::width(hDataType) << endl;
cout << "Height in rows: " << DataType::height(hDataType) << endl;
cout << "Bit depth: " << DataType::bitDepth(hDataType) << endl;
cout << "Bytes/line (stride): " << DataType::stride(hDataType) << endl;
// display the frame video format
VideoDataType::Format videoFormat = VideoDataType::format(hDataType);
cout << "Video format: " << VideoDataType::formatString(videoFormat).c_str() << endl;
// get a pointer to the frame data
}
pFrameData = hFrame->buffer()->data();
}
}
catch (GeneralException& e)
{
cout << e.what() << endl;
}
return pFrameData;
}
and main (I changed it a little bit) :
int main(int argc, char **argv)
{
QApplication app(argc, argv);
ControlWidget *controlWidget = new ControlWidget;
//controlWidget->show();
try
{
OsCam camera;
int i = 0;
for (int j = 0; j<10000 ; j++)
{
if ((camera.test_cam->liveFrameReady()))
{
Common::FrameHandle loaded = camera.test_cam->liveFrame()->clone();
camera.visualizeFrame(loaded);
controlWidget->update(loaded);
camera.set_shutter(0, 1, 3000 + i * 200);
loaded->~Frame();
}
i++;
}
}
catch (GeneralException& e)
{
std::cout << e.what() << std::endl;
int a;
std::cin >> a;
return 1;
}
}
After cv::named_window

Stack call: why is the cursor jumping to a specific position of the recursive function

Problem description
I am trying to solve the following problem:
Implement an algorithm to print all valid (e.g., properly opened and
closed) combinations of n-pairs of parentheses. EXAMPLE: input: 3
(e.g., 3 pairs of parentheses) output: ()()(), ()(()), (())(), ((()))
The moment I rearch the base case and when the calls are being popped from from stack, it is always jumping to following part of the code;
cout <<"==============> RESTART HERE " << endl;
Question
Why isn't the cursor returning to the beginning of the function after the return statement. Why is it restarting from cout <<"==============> RESTART HERE " << endl;
In this code for instance it always restarts from the beginning:
void HelloWorld(int count)
{
if(count<1) return;
if(count<0) return;
cout << " Hello World!" << endl;
HelloWorld(count - 1);
}
The following picture shows the call stack for the first run.
Source code
# include<stdio.h>
#include <iostream>
using namespace std;
# define MAX_SIZE 100
void _printParenthesis(int pos, int n, int open, int close);
/* Wrapper over _printParenthesis()*/
void printParenthesis(int n)
{
if(n > 0)
_printParenthesis(0, n, 0, 0);
return;
}
void _printParenthesis(int pos, int n, int open, int close)
{
static char str[MAX_SIZE];
if(close == n)
{
cout <<" open " << open <<" close " << close <<" " << pos<< endl;
cout << str << endl;
return;
}
else
{
if(close < open) {
str[pos] = '}';
cout <<" B open " << open <<" close " << close <<" " << pos<< " }" << endl;
_printParenthesis(pos+1, n, open, close+1);
}
cout <<"==============> RESTART HERE " << endl;
if(open < n) {
str[pos] = '{';
cout <<" A open " << open <<" close " << close <<" " <<pos << " {" << endl;
_printParenthesis(pos+1, n, open+1, close);
}
}
}
/* driver program to test above functions */
int main()
{
int n = 3;
printParenthesis(n);
getchar();
return 0;
}
You are probably running a debugger on optimized code. There's nothing wrong with doing that, but the optimizer may have reordered code. If the out-of-order execution bothers you, turn off the optimizer when you use the debugger.

Threading Segfault when reading members

I am facing some problems when I am trying to read a class variable in my worker thread (That variable was not created withing that thread). Here is my class header with static worker thread function:
class C1WTempReader
{
public:
C1WTempReader(std::string device);
virtual ~C1WTempReader();
void startTemRead();
double& getTemperature();
private:
std::string device;
std::string path;
double temperature;
pthread_t w1Thread;
std::mutex w1Mutex;
bool fileExists(const std::string& filename);
static void * threadHelper(void * arg)
{
return ((C1WTempReader*) arg)->tempReadRun(NULL);
}
void* tempReadRun(void* arg);
};
Here are the crucial methods I am using:
C1WTempReader::C1WTempReader(std::string device)
{
path = W1_PATH + device + W1_SLAVE;
if (!fileExists(path))
{
std::cout << "File " << path << " doesnt exist!" << std::endl;
path.clear();
return;
}
std::cout << "1 wire termometer device path: " << path << std::endl;
}
void C1WTempReader::startTempRead()
{
if(pthread_create(&w1Thread, NULL, threadHelper, NULL) == -1)
{
std::cout << "1W thread creation failed" << std::endl;
}
}
void* C1WTempReader::tempReadRun(void* arg)
{
w1Mutex.lock(); // SEGFAULT
std::string line;
std::ifstream myfile (path.c_str());
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
size_t found = line.find("t=");
if (found != std::string::npos)
{
found += 2;
std::string temp = line.substr(found, 10);
temperature = atof(temp.c_str());
temperature /= 1000;
std::cout << "Temperature: " << temperature << " *C" << std::endl;
}
line.clear();
}
myfile.close();
}
else
{
std::cout << "Unable to open file" << std::endl;
temperature = 1000; // bad value
}
w1Mutex.unlock();
return NULL;
}
double& C1WTempReader::getTemperature()
{
if (pthread_join(w1Thread, NULL))
{
std::cout << "1W Unable to join thread!" << std::endl;
}
return temperature;
}
Segmentation fault happens in the tempReadRun method, as soon as I try to lock the mutex. I didnt have mutexes before and I noticed that it happens whenever I try to read any of the class variables that are created ruring the class creation and are not created within the new thread. What Am I doing wrong?
And heres how I am trying to run this:
string device = "28-00000713a636";
C1WTempReader tempReader(device);
tempReader.startTempRead();
.
.
.
double temp = tempReader.getTemperature();
I have found what the problem was. In the function C1WTempReader::startTempRead():
if(pthread_create(&w1Thread, NULL, threadHelper, NULL) == -1)
{
std::cout << "1W thread creation failed" << std::endl;
}
The last argument of pthread_create had to be changed to this.
You are not passing argument to pthread_create:
if(pthread_create(&w1Thread, NULL, threadHelper, this) == -1)

Reading in Wav header - Not setting data size

I'm trying to read in the Header information of a .wav file.
If I have a .wav file that has a low sample rate (22050) it will read all the information in perfectly, however, if I have a higher Sample Rate (8000) then it fails to read in some information:
"dataSize" set's when using a 22050 .wav file however, when using a 8000 .wav file it does not get set and just displays some random numbers.. e.g. "1672494080" when the actual size is around 4k-4.5k in size.
Any suggestions to where I am going wrong?
EDIT:
#include <iostream>
#include <fstream>
#include <vector>
#include <inttypes.h>
#include <stdint.h>
#include <math.h>
using namespace std;
struct riff_hdr
{
char id[4];
uint32_t size;
char type[4];
};
struct chunk_hdr
{
char id[4];
uint32_t size;
};
struct wavefmt
{
uint16_t format_tag;
uint16_t channels;
uint32_t sample_rate;
uint32_t avg_bytes_sec;
uint16_t block_align;
uint16_t bits_per_sample;
uint16_t extra_size;
};
riff_hdr riff;
chunk_hdr chunk;
wavefmt fmt = {0};
uint32_t padded_size;
vector<uint8_t> chunk_data;
bool readHeader(ifstream &file) {
file.read(reinterpret_cast<char*>(&riff), sizeof(riff));
if (memcmp(riff.id, "RIFF", 4) == 0)
{
cout << "size=" << riff.size << endl;
cout << "id=" << string(riff.type, 4) << endl;
if (memcmp(riff.type, "WAVE", 4) == 0)
{
// chunks can be in any order!
// there is no guarantee that "fmt" is the first chunk.
// there is no guarantee that "fmt" is immediately followed by "data".
// There can be other chunks present!
do {
file.read(reinterpret_cast<char*>(&chunk), sizeof(chunk));
padded_size = ((chunk.size + 2 - 1) & ~1);
cout << "id=" << string(chunk.id, 4) << endl;
cout << "size=" << chunk.size << endl;
cout << "padded size=" << padded_size << endl;
if (memcmp(chunk.id, "fmt\0", 4) == 0)
{
if (chunk.size < sizeof(wavefmt))
{
// error!
file.ignore(padded_size);
}else{
// THIS block doesn't seem to be executing
chunk_data.resize(padded_size);
file.read(reinterpret_cast<char*>(&chunk_data[0]), padded_size);
fmt = *(reinterpret_cast<wavefmt*>(&chunk_data[0]));
cout << "format_tag=" << fmt.format_tag << endl;
cout << "channels=" << fmt.channels << endl;
cout << "sample_rate=" << fmt.sample_rate << endl;
cout << "avg_bytes_sec=" << fmt.avg_bytes_sec << endl;
cout << "block_align=" << fmt.block_align << endl;
cout << "bits_per_sample=" << fmt.bits_per_sample << endl;
cout << "extra_size=" << fmt.extra_size << endl;
}
if(fmt.format_tag != 1)
{
uint8_t *extra_data = &chunk_data[sizeof(wavefmt)];
}
}else if(memcmp(chunk.id, "data", 4) == 0) {
file.ignore(padded_size);
}else{
file.ignore(padded_size);
}
}while ((!file) && (!file.eof()));
}
}
return true;
}
int main()
{
ifstream file("example2.wav");
readHeader(file);
return 0;
}
OUTPUT:
size=41398
id=WAVE
id=fmt
size=18
padded size=18
chunk_data size=0
Where am I going wrong?
You have two problems with your code:
There is a 2-byte integer after the bitsPerSample value that you are not reading. It specifies the size of any extra data in that chunk. If the value of format2 indicates a PCM format only, you can ignore the value of the integer (it will usually be 0 anyway, but it may also be garbage), but you still have to account for its presense. The integer cannot be ignored for non-PCM formats, you have to read the value and then read how many bytes it says. You need to make sure you are reading the entire chunk before then entering your while loop, otherwise you will not be on the correct starting position in the file to read further chunks.
You are not taking into account that chunks are padded to the nearest WORD boundary, but the chunk size does not include any padding. When you call seekg(), you need to round the value up to the next WORD boundary.
Update: based on the new code you posted, it should look more like this instead:
#include <iostream>
#include <fstream>
#include <vector>
#include <inttypes.h>
#include <stdint.h>
#include <math.h>
using namespace std;
// if your compiler does not have pshpack1.h and poppack.h, then
// use #pragma pack instead. It is important that these structures
// be byte-alignd!
#include <pshpack1.h>
struct s_riff_hdr
{
char id[4];
uint32_t size;
char type[4];
};
struct s_chunk_hdr
{
char id[4];
uint32_t size;
};
struct s_wavefmt
{
uint16_t format_tag;
uint16_t channels;
uint32_t sample_rate;
uint32_t avg_bytes_sec;
uint16_t block_align;
};
struct s_wavefmtex
{
s_wavefmt fmt;
uint16_t bits_per_sample;
uint16_t extra_size;
};
struct s_pcmwavefmt
{
s_wavefmt fmt;
uint16_t bits_per_sample;
};
#include <poppack.h>
bool readWave(ifstream &file)
{
s_riff_hdr riff_hdr;
s_chunk_hdr chunk_hdr;
uint32_t padded_size;
vector<uint8_t> fmt_data;
s_wavefmt *fmt = NULL;
file.read(reinterpret_cast<char*>(&riff_hdr), sizeof(riff_hdr));
if (!file) return false;
if (memcmp(riff_hdr.id, "RIFF", 4) != 0) return false;
cout << "size=" << riff_hdr.size << endl;
cout << "type=" << string(riff_hdr.type, 4) << endl;
if (memcmp(riff_hdr.type, "WAVE", 4) != 0) return false;
// chunks can be in any order!
// there is no guarantee that "fmt" is the first chunk.
// there is no guarantee that "fmt" is immediately followed by "data".
// There can be other chunks present!
do
{
file.read(reinterpret_cast<char*>(&chunk_hdr), sizeof(chunk_hdr));
if (!file) return false;
padded_size = ((chunk_hdr.size + 1) & ~1);
cout << "id=" << string(chunk_hdr.id, 4) << endl;
cout << "size=" << chunk_hdr.size << endl;
cout << "padded size=" << padded_size << endl;
if (memcmp(chunk_hdr.id, "fmt ", 4) == 0)
{
if (chunk_hdr.size < sizeof(s_wavefmt)) return false;
fmt_data.resize(padded_size);
file.read(reinterpret_cast<char*>(&fmt_data[0]), padded_size);
if (!file) return false;
fmt = reinterpret_cast<s_wavefmt*>(&fmt_data[0]);
cout << "format_tag=" << fmt->format_tag << endl;
cout << "channels=" << fmt->channels << endl;
cout << "sample_rate=" << fmt->sample_rate << endl;
cout << "avg_bytes_sec=" << fmt->avg_bytes_sec << endl;
cout << "block_align=" << fmt->block_align << endl;
if (fmt->format_tag == 1) // PCM
{
if (chunk_hdr.size < sizeof(s_pcmwavefmt)) return false;
s_pcmwavefmt *pcm_fmt = reinterpret_cast<s_pcmwavefmt*>(fmt);
cout << "bits_per_sample=" << pcm_fmt->bits_per_sample << endl;
}
else
{
if (chunk_hdr.size < sizeof(s_wavefmtex)) return false;
s_wavefmtex *fmt_ex = reinterpret_cast<s_wavefmtex*>(fmt);
cout << "bits_per_sample=" << fmt_ex->bits_per_sample << endl;
cout << "extra_size=" << fmt_ex->extra_size << endl;
if (fmt_ex->extra_size != 0)
{
if (chunk_hdr.size < (sizeof(s_wavefmtex) + fmt_ex->extra_size)) return false;
uint8_t *extra_data = reinterpret_cast<uint8_t*>(fmt_ex + 1);
// use extra_data, up to extra_size bytes, as needed...
}
}
}
else if (memcmp(chunk_hdr.id, "data", 4) == 0)
{
// process chunk data, according to fmt, as needed...
file.ignore(padded_size);
if (!file) return false;
}
else
{
// process other chunks as needed...
file.ignore(padded_size);
if (!file) return false;
}
}
while (!file.eof());
return true;
}
int main()
{
ifstream file("example2.wav");
readWave(file);
return 0;
}