使用 fopen_s读取一个wav文件并对其求WVD并输出WVD结果不使用库函数C语言并解释代码
时间: 2024-04-30 15:20:57 浏览: 61
下面是一个使用 C 语言读取 WAV 文件并计算其 WVD 的示例代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define PI 3.14159265358979323846
typedef struct {
char chunkId[4];
unsigned int chunkSize;
char format[4];
char subchunk1Id[4];
unsigned int subchunk1Size;
unsigned short audioFormat;
unsigned short numChannels;
unsigned int sampleRate;
unsigned int byteRate;
unsigned short blockAlign;
unsigned short bitsPerSample;
char subchunk2Id[4];
unsigned int subchunk2Size;
} WavHeader;
int main() {
FILE *fp;
WavHeader header;
char filename[256];
double **data;
int i, j, k;
double *window;
int windowSize = 1024;
int hopSize = 256;
int numWindows;
double **wvd;
// Read WAV file header
printf("Enter WAV file name: ");
scanf("%s", filename);
if (fopen_s(&fp, filename, "rb") != 0) {
printf("Cannot open file.\n");
return 1;
}
fread(&header, sizeof(WavHeader), 1, fp);
printf("Sample rate: %u Hz\n", header.sampleRate);
printf("Number of channels: %hu\n", header.numChannels);
printf("Bits per sample: %hu\n", header.bitsPerSample);
// Allocate memory for audio data
data = (double **) malloc(header.numChannels * sizeof(double *));
for (i = 0; i < header.numChannels; i++) {
data[i] = (double *) malloc(header.subchunk2Size / header.blockAlign * sizeof(double));
}
// Read audio data
for (i = 0; i < header.subchunk2Size / header.blockAlign; i++) {
for (j = 0; j < header.numChannels; j++) {
switch (header.bitsPerSample) {
case 8:
data[j][i] = (double) ((int16_t) fgetc(fp) - 128) / 128.0;
break;
case 16:
data[j][i] = (double) ((int16_t) fgetc(fp)) / 32768.0;
data[j][i] += (double) ((int16_t) fgetc(fp)) / 32768.0 / 256.0;
break;
case 24:
data[j][i] = (double) ((int16_t) fgetc(fp)) / 8388608.0;
data[j][i] += (double) ((int16_t) fgetc(fp)) / 32768.0 / 256.0;
data[j][i] += (double) ((int16_t) fgetc(fp)) / 32768.0 / 65536.0;
break;
case 32:
data[j][i] = (double) ((int16_t) fgetc(fp)) / 2147483648.0;
data[j][i] += (double) ((int16_t) fgetc(fp)) / 32768.0 / 65536.0;
data[j][i] += (double) ((int16_t) fgetc(fp)) / 32768.0 / 4294967296.0;
data[j][i] += (double) ((int16_t) fgetc(fp)) / 32768.0 / 1099511627776.0;
break;
}
}
}
// Calculate WVD
numWindows = (header.subchunk2Size / header.blockAlign - windowSize) / hopSize + 1;
window = (double *) malloc(windowSize * sizeof(double));
wvd = (double **) malloc(numWindows * sizeof(double *));
for (i = 0; i < numWindows; i++) {
wvd[i] = (double *) malloc(windowSize * windowSize * sizeof(double));
}
for (i = 0; i < windowSize; i++) {
window[i] = 0.5 - 0.5 * cos(2.0 * PI * i / (windowSize - 1));
}
for (i = 0; i < numWindows; i++) {
for (j = 0; j < windowSize; j++) {
for (k = 0; k < windowSize; k++) {
double sum = 0.0;
int n;
for (n = 0; n < windowSize; n++) {
int m = i * hopSize + n;
if (m >= 0 && m < header.subchunk2Size / header.blockAlign) {
sum += data[0][m] * data[0][m - k] * window[n];
}
}
wvd[i][j * windowSize + k] = sum;
}
}
}
// Output WVD
FILE *fpOut;
char filenameOut[256];
sprintf(filenameOut, "%s.wvd", filename);
if (fopen_s(&fpOut, filenameOut, "wb") != 0) {
printf("Cannot open file for writing.\n");
return 1;
}
fwrite(&header, sizeof(WavHeader), 1, fpOut);
for (i = 0; i < numWindows; i++) {
fwrite(wvd[i], sizeof(double), windowSize * windowSize, fpOut);
}
fclose(fpOut);
// Free memory
free(window);
for (i = 0; i < numWindows; i++) {
free(wvd[i]);
}
free(wvd);
for (i = 0; i < header.numChannels; i++) {
free(data[i]);
}
free(data);
fclose(fp);
return 0;
}
```
这段代码中,我们首先定义了一个结构体 `WavHeader` 来存储 WAV 文件头信息。然后使用 `fopen_s` 函数打开 WAV 文件,读取文件头信息并打印出来。接着分配内存用来存储音频数据,读取 WAV 文件中的音频数据并存储到内存中。接下来计算 WVD,这里使用了固定大小的窗口和重叠方式来分割音频信号,并在每个窗口上计算 WVD。最后将 WVD 结果写入到一个新的 WAV 文件中。
值得注意的是,这段代码只支持 16、24、32 位的 WAV 文件,如果需要支持其他格式的 WAV 文件需要相应地修改代码。
阅读全文