我是个新手,我写了一些代码,可以获取WAV文件,并将原始数据(仅为PCM数据)导出到*.raw文件。但我对这个结构很困惑。代码是作为一个过程(LISP样式)编写的,并且没有函数。我能得到一些如何重组代码的建议吗?
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wave.h"
byte buf[5]; // 4 char string buffer
char filename[200]; //
FILE *fp;
FILE *pcm_data;
int main(int argc, char *argv[])
{
strcat(filename, argv[1]);
struct riff_chunk riff = {"RIFF", 0, "WAVE"};
struct fmt_chunk fmt = {"fmt "};
struct data_chunk data = {"data"};
if ((fp = fopen(argv[1], "rb"))==NULL) {
printf("Can't open the file. Exit.\n");
return 1;
}
// Reading RIFF section
if (fread(&riff.id, sizeof(byte), 12, fp)!= 12) {
printf("Can't read RIFF chunk or EOF is met. Exit.\n");
return 1;
} else {
memccpy(buf, riff.id, '\0', 4);
if (strcmp(buf, "RIFF")!=0) {
printf("File format is not RIFF. Exit.\n");
return 1;
}
memccpy(buf, riff.type, '\0', 4);
if (strcmp(buf, "WAVE")!=0) {
printf("File format is not WAVE. Exit.\n");
return 1;
}
};
// Reading fmt.id and fmt.size
if (fread(&fmt, sizeof(byte), 8, fp)!=8) {
printf("Can't read fmt chunk or EOF is met. Exit.\n");
return 1;
} else {
memccpy(buf, fmt.id, '\0', 4);
if (strcmp(buf, "fmt ")!=0) {
printf("File have no fmt chunk. Exit.\n");
return 1;
}
}
// Reading fmt Sample Format Info
if (fread(&fmt.compression, sizeof(byte), fmt.size, fp) != fmt.size) {
printf("Can't read Sample Format Info in fmt chunk or EOF is met. Exit.\n");
return 1;
}
printf("Compression: %d\n", fmt.compression);
printf("Channels: %d\n", fmt.chanels);
printf("Sample Rate: %d\n", fmt.sample_rate);
printf("Bit Rate: %d\n", fmt.bit_per_sample);
// Reading data/some chunk
if (fread(&data, sizeof(byte), 8, fp)!=8) {
printf("Error of reading data chunk. Exit.\n");
return 1;
} else {
while (memccpy(buf, data.id, '\0', 4), strcmp(buf, "data")!=0) {
fseek(fp, data.size, 1); // перемещаем указатель файла на конец чанка (его размер)
fread(&data, sizeof(byte), 8, fp);
}
}
// Reading PCM
byte *dump = (byte*)malloc(data.size);
if (dump == NULL) {
printf("Allocation memory error");
return 1;
}
if (fmt.compression == 1) {
fmt.number_of_blocks = data.size / fmt.block_align;
if ((fread(dump, fmt.block_align, fmt.number_of_blocks, fp))!=fmt.number_of_blocks) {
printf("Readin PCM data error.\n");
return 1;
} else {
strcat(filename, ".raw");
if ((pcm_data = fopen(filename, "wb"))==NULL) {
printf("Can't open the PCM file for write. Exit.\n");
return 1;
}
if(fwrite(dump, fmt.block_align, fmt.number_of_blocks, pcm_data)!=fmt.number_of_blocks) {
printf("Can't write PCM file. Exit.\n");
return 1;
}
printf("------------\nDone. PCM data writing in PCM file. Exit.\n");
}
} else {
printf("Compression type is not PCM. Exit.\n");
return 1;
}
free(dump);
fclose(fp);
fclose(pcm_data);
return 0;
}wave.h
typedef char byte; // 1 byte \ 8 bit
typedef short int word; // 2 byte \ 16 bit
typedef unsigned int dword; // 4 byte \ 32 bit
struct riff_chunk
{
byte id[4]; // 4b "RIFF" string >|
dword size; // 4b |-> 12 byte
byte type[4]; // 4b "WAVE" string >|
};
struct fmt_chunk
{
byte id[4]; // 4b "fmt" string
dword size; // 4b _____
word compression; // 2b
word chanels; // 2b
dword sample_rate; // 4b _____
dword byte_per_sec; // 4b
word block_align; // 2b
word bit_per_sample; // 2b _____
word extra_format_size; // 2b _____
byte* extra_format_data; // 8b _____
dword number_of_blocks; // 4b _____
};
struct data_chunk
{
byte id[4]; // 4 "data" string
dword size; // 4
};
int dump(word*, dword*);发布于 2019-06-11 09:04:11
除了消除不必要的全局变量(大多数可以移到函数作用域)之外,我不认为非常需要重新组织代码的结构。
有一些可移植性问题需要解决。我将从整数类型宽度的假设开始:
*
这些注释是假设,需要为您构建的每个平台进行验证。有一种便携的方法可以得到你想要的东西:
typedef uint8_t byte;
typedef uint16_t word;
typedef uint32_t dword;或者只是在整个过程中使用标准的固定宽度类型--这比发明自己的术语更容易混淆。
注意,当使用printf()和系列时,我们需要使用正确的说明符。这是错误的:
printf(“压缩:%d\n",fmt.compression);printf(”通道:%d\n",fmt.chanels);printf(“采样率:%d\n",fmt.sample_rate);
对于最初的定义,我们应该对前两个使用%hu,对于最后两个应该使用%u。使用标准的固定宽度类型,我们可以获得可用于格式化的宏:
printf("Compression: %" PRIu16 "\n", fmt.compression);
printf("Channels: %" PRIu16 "\n", fmt.chanels);
printf("Sample Rate: %" PRIu32 "\n", fmt.sample_rate);
printf("Bit Rate: %" PRIu32 "\n", fmt.bit_per_sample);以下是一个效率低下的问题:
memccpy(buf, riff.id, '\0', 4);
if (strcmp(buf, "RIFF")!=0) {首先,memccpy不是标准C(尽管它是由POSIX定义的),因此可移植性略有降低。但是这里不需要复制到buf --只需使用strncmp()进行比较:
if (strncmp("RIFF", riff.id, sizeof riff.id)) {有很多硬编码的尺寸。例如:
if (fread(&riff.id,sizeof(字节),12,fp)= 12) {
我们编写sizeof (byte)是很奇怪的,尽管byte只是char的别名(因此大小为1 char),但是在我们可以更有意义地编写sizeof riff的地方使用12:
if (fread(&riff, 1, sizeof riff, fp) != sizeof riff) {(我还将&riff.id更改为&riff,以表明我们是为整个结构编写的,而不仅仅是id成员。)
在分配时,不需要将返回的void指针转换为更具体的指针大小(也可能有轻微的损害)。使用非空指针的固有真实性也是惯用的,而不是显式地针对NULL进行测试:
byte *dump = malloc(data.size);
if (!dump) {我很高兴您没有忘记这里的错误检查,并且在打开文件时--这是C语言编程的一个重要部分,这是正确的。一个小改进是:错误消息应该转到stderr,而不是stdout:
fprintf(stderr, "Memory allocation error\n");顺便说一句,在编译时不要忘记,以确保结构是打包的,没有成员之间的任何填充。
增强建议:允许用户指定写入输出的位置(或将其发送到标准输出,并让他们使用shell重定向输出)。如果输入文件目前位于只读目录中,我们将失败。
https://codereview.stackexchange.com/questions/222026
复制相似问题