c - 读取可能未对齐数据的 WAV 文件



>我正在尝试从波形文件数据库中读取音频波形文件。我用于读取波形文件的代码如下所示

    /**
 * Read and parse a wave file
 *
 **/
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "wave.h"
#define TRUE 1 
#define FALSE 0
// WAVE header structure
unsigned char buffer4[4];
unsigned char buffer2[2];
char* seconds_to_time(float seconds);

 FILE *ptr;
 char *filename;
 struct HEADER header;
int main(int argc, char **argv) {
 filename = (char*) malloc(sizeof(char) * 1024);
 if (filename == NULL) {
   printf("Error in mallocn");
   exit(1);
 }
 // get file path
 char cwd[1024];
 if (getcwd(cwd, sizeof(cwd)) != NULL) {
    strcpy(filename, cwd);
    // get filename from command line
    if (argc < 2) {
      printf("No wave file specifiedn");
      return;
    }
    strcat(filename, "/");
    strcat(filename, argv[1]);
    printf("%sn", filename);
 }
 // open file
 printf("Opening  file..n");
 ptr = fopen(filename, "rb");
 if (ptr == NULL) {
    printf("Error opening filen");
    exit(1);
 }
 int read = 0;
 // read header parts
 read = fread(header.riff, sizeof(header.riff), 1, ptr);
 printf("(1-4): %s n", header.riff); 
 read = fread(buffer4, sizeof(buffer4), 1, ptr);
 printf("%u %u %u %un", buffer4[0], buffer4[1], buffer4[2], buffer4[3]);
 // convert little endian to big endian 4 byte int
 header.overall_size  = buffer4[0] | 
                        (buffer4[1]<<8) | 
                        (buffer4[2]<<16) | 
                        (buffer4[3]<<24);
 printf("(5-8) Overall size: bytes:%u, Kb:%u n", header.overall_size, header.overall_size/1024);
 read = fread(header.wave, sizeof(header.wave), 1, ptr);
 printf("(9-12) Wave marker: %sn", header.wave);
 read = fread(header.fmt_chunk_marker, sizeof(header.fmt_chunk_marker), 1, ptr);
 printf("(13-16) Fmt marker: %sn", header.fmt_chunk_marker);
 read = fread(buffer4, sizeof(buffer4), 1, ptr);
 printf("%u %u %u %un", buffer4[0], buffer4[1], buffer4[2], buffer4[3]);
 // convert little endian to big endian 4 byte integer
 header.length_of_fmt = buffer4[0] |
                            (buffer4[1] << 8) |
                            (buffer4[2] << 16) |
                            (buffer4[3] << 24);
 printf("(17-20) Length of Fmt header: %u n", header.length_of_fmt);
 read = fread(buffer2, sizeof(buffer2), 1, ptr); printf("%u %u n", buffer2[0], buffer2[1]);
 header.format_type = buffer2[0] | (buffer2[1] << 8);
 char format_name[10] = "";
 if (header.format_type == 1)
   strcpy(format_name,"PCM"); 
 else if (header.format_type == 6)
  strcpy(format_name, "A-law");
 else if (header.format_type == 7)
  strcpy(format_name, "Mu-law");
 printf("(21-22) Format type: %u %s n", header.format_type, format_name);
 read = fread(buffer2, sizeof(buffer2), 1, ptr);
 printf("%u %u n", buffer2[0], buffer2[1]);
 header.channels = buffer2[0] | (buffer2[1] << 8);
 printf("(23-24) Channels: %u n", header.channels);
 read = fread(buffer4, sizeof(buffer4), 1, ptr);
 printf("%u %u %u %un", buffer4[0], buffer4[1], buffer4[2], buffer4[3]);
 header.sample_rate = buffer4[0] |
                        (buffer4[1] << 8) |
                        (buffer4[2] << 16) |
                        (buffer4[3] << 24);
 printf("(25-28) Sample rate: %un", header.sample_rate);
 read = fread(buffer4, sizeof(buffer4), 1, ptr);
 printf("%u %u %u %un", buffer4[0], buffer4[1], buffer4[2], buffer4[3]);
 header.byterate  = buffer4[0] |
                        (buffer4[1] << 8) |
                        (buffer4[2] << 16) |
                        (buffer4[3] << 24);
 printf("(29-32) Byte Rate: %u , Bit Rate:%un", header.byterate, header.byterate*8);
 read = fread(buffer2, sizeof(buffer2), 1, ptr);
 printf("%u %u n", buffer2[0], buffer2[1]);
 header.block_align = buffer2[0] |
                    (buffer2[1] << 8);
 printf("(33-34) Block Alignment: %u n", header.block_align);
 read = fread(buffer2, sizeof(buffer2), 1, ptr);
 printf("%u %u n", buffer2[0], buffer2[1]);
 header.bits_per_sample = buffer2[0] |
                    (buffer2[1] << 8);
 printf("(35-36) Bits per sample: %u n", header.bits_per_sample);
 read = fread(header.data_chunk_header, sizeof(header.data_chunk_header), 1, ptr);
 printf("(37-40) Data Marker: %s n", header.data_chunk_header);
 read = fread(buffer4, sizeof(buffer4), 1, ptr);
 printf("%u %u %u %un", buffer4[0], buffer4[1], buffer4[2], buffer4[3]);
 header.data_size = buffer4[0] |
                (buffer4[1] << 8) |
                (buffer4[2] << 16) | 
                (buffer4[3] << 24 );
 printf("(41-44) Size of data chunk: %u n", header.data_size);

 // calculate no.of samples
 long num_samples = (8 * header.data_size) / (header.channels * header.bits_per_sample);
 printf("Number of samples:%lu n", num_samples);
 long size_of_each_sample = (header.channels * header.bits_per_sample) / 8;
 printf("Size of each sample:%ld bytesn", size_of_each_sample);
 // calculate duration of file
 float duration_in_seconds = (float) header.overall_size / header.byterate;
 printf("Approx.Duration in seconds=%fn", duration_in_seconds);
 printf("Approx.Duration in h:m:s=%sn", seconds_to_time(duration_in_seconds));

 // read each sample from data chunk if PCM
 if (header.format_type == 1) { // PCM
    printf("Dump sample data? Y/N?");
    char c = 'n';
    scanf("%c", &c);
    if (c == 'Y' || c == 'y') { 
        long i =0;
        char data_buffer[size_of_each_sample];
        int  size_is_correct = TRUE;
        // make sure that the bytes-per-sample is completely divisible by num.of channels
        long bytes_in_each_channel = (size_of_each_sample / header.channels);
        if ((bytes_in_each_channel  * header.channels) != size_of_each_sample) {
            printf("Error: %ld x %ud <> %ldn", bytes_in_each_channel, header.channels, size_of_each_sample);
            size_is_correct = FALSE;
        }
        if (size_is_correct) { 
                    // the valid amplitude range for values based on the bits per sample
            long low_limit = 0l;
            long high_limit = 0l;
            switch (header.bits_per_sample) {
                case 8:
                    low_limit = -128;
                    high_limit = 127;
                    break;
                case 16:
                    low_limit = -32768;
                    high_limit = 32767;
                    break;
                case 32:
                    low_limit = -2147483648;
                    high_limit = 2147483647;
                    break;
            }                   
            printf("nn.Valid range for data values : %ld to %ld n", low_limit, high_limit);
            for (i =1; i <= num_samples; i++) {
                printf("==========Sample %ld / %ld=============n", i, num_samples);
                read = fread(data_buffer, sizeof(data_buffer), 1, ptr);
                if (read == 1) {
                    // dump the data read
                    unsigned int  xchannels = 0;
                    int data_in_channel = 0;
                    for (xchannels = 0; xchannels < header.channels; xchannels ++ ) {
                        printf("Channel#%d : ", (xchannels+1));
                        // convert data from little endian to big endian based on bytes in each channel sample
                        if (bytes_in_each_channel == 4) {
                            data_in_channel =   data_buffer[0] | 
                                                (data_buffer[1]<<8) | 
                                                (data_buffer[2]<<16) | 
                                                (data_buffer[3]<<24);
                        }
                        else if (bytes_in_each_channel == 2) {
                            data_in_channel = data_buffer[0] |
                                                (data_buffer[1] << 8);
                        }
                        else if (bytes_in_each_channel == 1) {
                            data_in_channel = data_buffer[0];
                        }
                        printf("%d ", data_in_channel);
                        // check if value was in range
                        if (data_in_channel < low_limit || data_in_channel > high_limit)
                            printf("**value out of rangen");
                        printf(" | ");
                    }
                    printf("n");
                }
                else {
                    printf("Error reading file. %d bytesn", read);
                    break;
                }
            } //    for (i =1; i <= num_samples; i++) {
        } //    if (size_is_correct) { 
     } // if (c == 'Y' || c == 'y') { 
 } //  if (header.format_type == 1) { 
 printf("Closing file..n");
 fclose(ptr);
  // cleanup before quitting
 free(filename);
 return 0;
}
/**
 * Convert seconds into hh:mm:ss format
 * Params:
 *  seconds - seconds value
 * Returns: hms - formatted string
 **/
 char* seconds_to_time(float raw_seconds) {
  char *hms;
  int hours, hours_residue, minutes, seconds, milliseconds;
  hms = (char*) malloc(100);
  sprintf(hms, "%f", raw_seconds);
  hours = (int) raw_seconds/3600;
  hours_residue = (int) raw_seconds % 3600;
  minutes = hours_residue/60;
  seconds = hours_residue % 60;
  milliseconds = 0;
  // get the decimal part of raw_seconds to get milliseconds
  char *pos;
  pos = strchr(hms, '.');
  int ipos = (int) (pos - hms);
  char decimalpart[15];
  memset(decimalpart, ' ', sizeof(decimalpart));
  strncpy(decimalpart, &hms[ipos+1], 3);
  milliseconds = atoi(decimalpart); 

  sprintf(hms, "%d:%d:%d.%d", hours, minutes, seconds, milliseconds);
  return hms;
}

包含的 wave.h 如下所示

// WAVE file header format
struct HEADER {
    unsigned char riff[4];                      // RIFF string
    unsigned int overall_size   ;               // overall size of file in bytes
    unsigned char wave[4];                      // WAVE string
    unsigned char fmt_chunk_marker[4];          // fmt string with trailing null char
    unsigned int length_of_fmt;                 // length of the format data
    unsigned int format_type;                   // format type. 1-PCM, 3- IEEE float, 6 - 8bit A law, 7 - 8bit mu law
    unsigned int channels;                      // no.of channels
    unsigned int sample_rate;                   // sampling rate (blocks per second)
    unsigned int byterate;                      // SampleRate * NumChannels * BitsPerSample/8
    unsigned int block_align;                   // NumChannels * BitsPerSample/8
    unsigned int bits_per_sample;               // bits per sample, 8- 8bits, 16- 16 bits etc
    unsigned char data_chunk_header [4];        // DATA string or FLLR string
    unsigned int data_size;                     // NumSamples * NumChannels * BitsPerSample/8 - size of the next chunk that will be read
};

.我尝试过其他 wav 文件,似乎得到了正确的输出(即标题中的"RIFF"和"WAVE"(。但是,我关心的是输出

    ________________________________________________________________________________~/Downloads/libmfcc-master $: ./a.out audioclip-1523814201.wav 
/home/sfelde2/Downloads/libmfcc-master/audioclip-1523814201.wav
Opening  file..
(1-4):  
102 116 121 112
(5-8) Overall size: bytes:1887007846, Kb:1842781 
(9-12) Wave marker: isom
(13-16) Fmt marker: 
105 115 111 109
(17-20) Length of Fmt header: 1836020585 
105 115 
(21-22) Format type: 29545  
111 50 
(23-24) Channels: 12911 
109 112 52 49
(25-28) Sample rate: 825520237
0 0 0 8
(29-32) Byte Rate: 134217728 , Bit Rate:1073741824
102 114 
(33-34) Block Alignment: 29286 
101 101 
(35-36) Bits per sample: 25957 
(37-40) Data Marker:  
109 100 97 116
(41-44) Size of data chunk: 1952539757 
Number of samples:8 
Size of each sample:41891353 bytes
Approx.Duration in seconds=14.059304
Approx.Duration in h:m:s=0:0:14.59
Closing file..

我开始怀疑它说"isom"的波场是否可能表示它的对齐方式不同,但我无法在 ISOM 上找到任何东西。Thiiis 以及它没有打印 RIFF 字符串并吐出数据的错误值这一事实让我想知道是否有我可以弄清楚数据从哪里开始的事实。任何关于可能是什么问题的想法,或者如果有的话,我可以调试它,以便我可以使用 wav 文件,将不胜感激。

对于遇到此问题的任何人,我意识到数据在下载时被我的计算机自动转换。下载文件时,由于我不知道的某种原因,它们被转换为.png文件。为了避免这种情况,如果您遇到与我相同的问题,请确保检查您输入的文件类型,即使它以.wav结尾结尾。

最新更新