#c #wav #write
Вопрос:
У меня есть домашнее задание по WAV-файлам и FIR-фильтрам для класса цифровой обработки сигналов .
Моя программа должна прочитать файл WAV, применить фильтр к данным и снова записать выходные данные в другой файл WAV.
Я завершил чтение и применение фильтра, но не могу записать WAV-файл. Программа не выдает ошибок при компиляции, но WAV-файл не воспроизводится.
Если я напишу «temp» в WAV, он будет работать правильно. Но если я напишу «данные», это не так.
Как я могу правильно написать WAV-файл ?
#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", amp;nchannel, amp;ssample, amp;csample);
short* data = (short*)amp;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*)amp;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 bytesnn", filename, file_size);
char* buffer = (char*)malloc(sizeof(char) * file_size);
fread(buffer, file_size, 1, fp);
// Dump the buffer info.
*nchannel = *(short*)amp;buffer[22];
*ssample = *(short*)amp;buffer[34] / 8;
*csample = *(int*)amp;buffer[40] / *ssample;
printf("ChunkSize :t %un", *(int*)amp;buffer[4]);
printf("Format :t %un", *(short*)amp;buffer[20]);
printf("NumChannels :t %un", *(short*)amp;buffer[22]);
printf("SampleRate :t %un", *(int*)amp;buffer[24]); // number of samples per second
printf("ByteRate :t %un", *(int*)amp;buffer[28]); // number of bytes per second
printf("BitsPerSample :t %un", *(short*)amp;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 %un", *(int*)amp;buffer[40]); // size of data (byte)
printf("Duration :t %fsnn", (float)(*(int*)amp;buffer[40]) / *(int*)amp;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);
}
Комментарии:
1. Если вы прочитаете файл и запишете его без применения какого-либо фильтра, сможете ли вы прочитать (и прослушать) новый файл?
2. Файлы WAV нуждаются в предварительном заголовке, см.: документы. fileformat.com/audio/wav
3. В строке
write_wav("test.wav", out, csample * ssample WAV_HEADER_LENGTH);
используется переменнаяout
, которой не существует — это явно не тот код, который вы запускаете, поскольку он не будет компилироваться.4. Почему бы вам не использовать библиотеку для обработки форматирования файлов WAV? Такие, как github.com/mhroth/tinywav
5. @mmc055, поэтому вы должны исправить ошибку, отредактировав вопрос. Мы не можем ответить на вопрос о коде, который мы не видим, или о коде, который мы видим, но это не тот код, о котором вы спрашиваете! В частности, мы не можем видеть, что вы пишете.
Ответ №1:
Это работает для меня:
int main()
{
short nchannel, ssample;
int csample;
// Reading WAV file and returning the data.
char* temp = read_wav("sum.wav", amp;nchannel, amp;ssample, amp;csample);
short* data = (short*)amp;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*)amp;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);
}
Мои изменения:
- Основное изменение заключается в использовании полного буфера с крайне вводящим в заблуждение именем:
temp
, вместо вашегоout
, который не компилируется, в качестве аргументаwrite_wav
. - Я применил «свои» коэффициенты фильтра (звук из выходного файла действительно искажен),
- Я сделал свой любимый отступ
Если код должен быть переносимым, вам необходимо проверить окончание и действовать соответственно.
Я бы ожидал, что входные и выходные файлы будут одинаковой длины, но это не так. Пожалуйста, проверьте сами, почему это не так. Пример:
-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
Похоже, что в выходном файле не хватает 130 байт.
Ваш float filter[N]
с N
неизвестным во время компиляции является расширением C : пожалуйста, используйте std::vector
вместо этого в своем окончательном коде.
В следующий раз, пожалуйста, предоставьте также ссылку на любые входные файлы. Для своих тестов я использовал https://freewavesamples.com/alesis-fusion-clean-guitar-c3 , но все эти мелочи, такие как поиск входного файла (формат WAV имеет несколько вариантов, я мог пропустить правильный), угадывание параметров фильтра и т.д. Требуют времени и усилий.
Ваше условие if ((i - j) >= 0)
может быть записано более понятным способом; предпочтительно путем изменения «заголовка»внутреннего цикла.
Комментарии:
1. Я знаю, что «temp» работает правильно, потому что программа считывает wav и возвращает «temp». Вы установили «temp» в качестве параметра, тогда почему у нас есть «выход» ? Я должен установить «выход» в качестве параметра, чтобы увидеть разницу между входом и выходом.
2. Конечно, нет! Вывод-это просто ссылка на temp. Это тот же буфер памяти!
3. Вы должны выделить отдельный буфер для вывода. Я предлагаю, чтобы он содержал дополнительные 44 байта стандартного заголовка WAV.
memcopy
эти байты изtemp
или установите их вручную. Затем установите «звуковые» байты в соответствии с вашим фильтром. На данный момент вы используете «вывод» как входной, так и выходной буфер, что, по сути, неправильно.4.
data
,output
иtemp
ссылаются на ту же память (с немного разными начальными смещениями). Алгоритмически это не выглядит «кошерным», но, насколько я мог понять, вы спросили, почему ваши выходные файлы вообще не воспроизводились. Это другой вопрос. Из нашего разговора я сделал вывод, что вы, возможно, забыли добавить заголовок WAV в выходной файл.5. @mmc055, потому что тогда вы бы писали только образцы данных без заголовка метаданных. Тогда это не будет действительным WAV. Поскольку вы потрудились прочитать и отобразить данные заголовка, непонятно, почему это не очевидно, и тот факт, что код в вопросе не записывает ни временные, ни выходные данные (пока вы не отредактируете по запросу), не ясно, в чем ваша проблема, кроме вашего раскрывающего комментария.