'Writing to WAV file C++
I have a homework about WAV files and FIR filters for a Digital Signal Processing class.
My program must read a WAV file, apply a filter to the data and write the output data to another WAV file again.
I have completed reading and applying filters but I can't write the WAV file. The program doesn't give any errors while compiling but the WAV file doesn't play.
If I write "temp" to the WAV, it runs properly. But if I write "data", it doesn't.
How can I write a WAV file properly?
#define _CRT_SECURE_NO_WARNINGS
#define PI 3.14f
#define WAV_HEADER_LENGTH 44
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <fstream>
char* read_wav(const char* filename, short*, short*, int*);
void write_wav(const char* filename, const char*, int);
using namespace std;
int main()
{
short nchannel, ssample;
int csample;
//Reading WAV file and returning the data.
char* temp = read_wav("sum.wav", &nchannel, &ssample, &csample);
short* data = (short*)&temp[WAV_HEADER_LENGTH];
cout << "How many coefficients are there in filter ?" << endl;
int N;
cin >> N ;
float filter[N];
cout << "Type coefficients in filter." << endl;
for(int i=0; i<N;i++){
cin >> filter[i];
}
short* output = (short*)&temp[WAV_HEADER_LENGTH];
for(int i=0; i < csample; i++){
double sum = 0;
for(int j=0; j < N; j++){
if((i - j) >= 0)
sum += filter[j] * data[i-j];
}
output[i] = (short) sum;
}
write_wav("test.wav", out, csample * ssample + WAV_HEADER_LENGTH);
}
char* read_wav(const char* filename, short* nchannel, short* ssample, int* csample) {
//Reading the file.
FILE* fp = fopen(filename, "rb");
if (!fp) {
fprintf(stderr, "Couldn't open the file \"%s\"\n", filename);
exit(0);
}
fseek(fp, 0, SEEK_END);
int file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
printf("The file \"%s\" has %d bytes\n\n", filename, file_size);
char* buffer = (char*)malloc(sizeof(char) * file_size);
fread(buffer, file_size, 1, fp);
// Dump the buffer info.
*nchannel = *(short*)&buffer[22];
*ssample = *(short*)&buffer[34] / 8;
*csample = *(int*)&buffer[40] / *ssample;
printf("ChunkSize :\t %u\n", *(int*)&buffer[4]);
printf("Format :\t %u\n", *(short*)&buffer[20]);
printf("NumChannels :\t %u\n", *(short*)&buffer[22]);
printf("SampleRate :\t %u\n", *(int*)&buffer[24]); // number of samples per second
printf("ByteRate :\t %u\n", *(int*)&buffer[28]); // number of bytes per second
printf("BitsPerSample :\t %u\n", *(short*)&buffer[34]);
printf("Subchunk2ID :\t \"%c%c%c%c\"\n", buffer[36], buffer[37], buffer[38], buffer[39]); // marks beginning of the data section
printf("Subchunk2Size :\t %u\n", *(int*)&buffer[40]); // size of data (byte)
printf("Duration :\t %fs\n\n", (float)(*(int*)&buffer[40]) / *(int*)&buffer[28]);
fclose(fp);
return buffer;
}
void write_wav(const char* filename, const char* data, int len) {
FILE* fp = fopen(filename, "wb");
if (!fp) {
fprintf(stderr, "Couldn't open the file \"%s\"\n", filename);
exit(0);
}
fwrite(data, len, 1, fp);
fclose(fp);
}
Solution 1:[1]
This works for me:
int main()
{
short nchannel, ssample;
int csample;
// Reading WAV file and returning the data.
char* temp = read_wav("sum.wav", &nchannel, &ssample, &csample);
short* data = (short*)&temp[WAV_HEADER_LENGTH];
// cout << "How many coefficients are there in filter ?" << endl;
const int N = 2;
// cin >> N;
float filter[N] = {0.5, 0.75};
// cout << "Type coefficients in filter." << endl;
// for (int i = 0; i < N; i++)
// {
// cin >> filter[i];
// }
short* output = (short*)&temp[WAV_HEADER_LENGTH];
for (int i = 0; i < csample; i++)
{
double sum = 0;
for (int j = 0; j < N; j++)
{
if ((i - j) >= 0) sum += filter[j] * data[i - j];
}
output[i] = (short)sum;
}
write_wav("test.wav", (char*)temp, csample * ssample + WAV_HEADER_LENGTH);
}
My changes:
- The major change is to use the full buffer, with extremely misleading name:
temp, instead of youroutthat does not compile, as the argument ofwrite_wav. - I applied "my" filter coefficients (the sound from the output file is really distorted),
- I applied my favorite indentation
If the code is to be portable, you need to check the endiannes and act accordingly.
I would expect the input and output files to be of the same length, but they're not. Please check it yourself why this is not the case. Example:
-rw-r--r-- 1 zkoza zkoza 787306 06-23 14:09 sum.wav
-rw-r--r-- 1 zkoza zkoza 787176 06-23 14:16 test.wav
It looks like 130 bytes are missing in the output file.
Your float filter[N] with N not known at compile time is a C++ extension: please use std::vector in your final code instead.
Next time please provide also a link for any input files. For my tests, I used https://freewavesamples.com/alesis-fusion-clean-guitar-c3 , but all these little things, like finding an input file (WAV format has several flavors, I could have missed the correct one), guessing filter parameters etc. take time and effort.
Your condition if ((i - j) >= 0) can be written in a way easier to understand; preferably by changing the inner loop "header".
Solution 2:[2]
Had the same problem, solved without IE fallback.
This will make it behave more like just typing it in the 'Run' window:
Process.Start(new ProcessStartInfo("https://www.example.com") { UseShellExecute = true });
Note that I'm setting UseShellExecute = true
The default is supposed to be true on .Net Framework, and false on .Net Core
and UWP apps should not use this flag. see docs
(I was running on .Net Core)
Solution 3:[3]
You can open the URL using InternetExplorer which comes along with Windows OS.
Try This:
Process.Start("IEXPLORE",url);
Solution 4:[4]
For some use cases in Core, even if ProcessInfo.WorkingDirectory is set, Environment.CurrentDirectory also needs to be set: an unintuitive difference in APIs that will undoubtedly result in a lot of broken ported code and confusion.
Solution 5:[5]
I have this code in a windows forms application and it works fine:
var info = new ProcessStartInfo(url);
Process.Start(info);
Solution 6:[6]
try
{
Process.Start(url);
}
catch (Win32Exception)
{
Process.Start("IExplore.exe", url);
}
Specially since your dealing with XP, this is more than likely machine specific issue.
Solution 7:[7]
I get
System.ComponentModel.Win32Exception
For WPF Framework project (host=win7, x64).
Try this:
filename="https://www.example.com";
Process.Start(filename)
If the browser is not started add Process.Start("chrome.exe", filename) in catch block;
It will start the chrome browser with and tab with "https://www.example.com".
Here the complete example:
try
{
var runningProcess = Process.GetProcessesByName("chrome");
if (runningProcess.Length != 0)
{
Process.Start("chrome", filename);
return;
}
runningProcess = Process.GetProcessesByName("firefox");
if (runningProcess.Length != 0)
{
Process.Start("firefox", filename);
return;
}
runningProcess = Process.GetProcessesByName("iexplore");
if (runningProcess.Length != 0)
{
Process.Start("iexplore", filename);
return;
}
Process.Start(filename);
}
catch (System.ComponentModel.Win32Exception)
{
Process.Start("chrome.exe", filename);
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | zkoza |
| Solution 2 | |
| Solution 3 | Sudhakar Tillapudi |
| Solution 4 | fartwhif |
| Solution 5 | James R. |
| Solution 6 | Dayan |
| Solution 7 | juagicre |
