#include #include #include #include #include #include char printable_char (char c) { return (std::isprint(c) ? c : ' '); } std::string uint8_to_charstr(const uint8_t x) { std::stringstream ss; ss << "|" << printable_char(static_cast(x)) << " |" << std::hex << std::setfill('0') << std::setw(2) << static_cast(x) << " |" << std::setfill(' ') << std::setw(8) << "0x" << std::setfill('0') << std::setw(2) << static_cast(x) << "|" << std::setfill(' ') << std::setw(10) << std::dec << static_cast(x) << "|"; return ss.str(); } std::string uint16_to_charstr(const uint16_t x) { uint8_t buf[2]; buf[0] = static_cast (x >> 8); buf[1] = static_cast (x >> 0); std::stringstream ss; ss << "|" << printable_char(static_cast(buf[1])) << printable_char(static_cast(buf[0])) << " |" << std::hex << std::setfill('0') << std::setw(2) << static_cast(buf[1]) << "." << std::hex << std::setfill('0') << std::setw(2) << static_cast(buf[0]) << " |" << std::setfill(' ') << std::setw(6) << "0x" << std::setfill('0') << std::setw(4) << x << "|" << std::setfill(' ') << std::setw(10) << std::dec << x << "|"; return ss.str(); } std::string uint32_to_charstr(const uint32_t x) { uint8_t buf[4]; buf[0] = static_cast (x >> 24); buf[1] = static_cast (x >> 16); buf[2] = static_cast (x >> 8); buf[3] = static_cast (x >> 0); std::stringstream ss; ss << "|" << printable_char(static_cast(buf[3])) << printable_char(static_cast(buf[2])) << printable_char(static_cast(buf[1])) << printable_char(static_cast(buf[0])) << "|" << std::hex << std::setfill('0') << std::setw(2) << static_cast(buf[3]) << "." << std::hex << std::setfill('0') << std::setw(2) << static_cast(buf[2]) << "." << std::hex << std::setfill('0') << std::setw(2) << static_cast(buf[1]) << "." << std::hex << std::setfill('0') << std::setw(2) << static_cast(buf[0]) << "|" << std::setfill('0') << std::setw(2) << "0x" << std::setfill('0') << std::setw(8) << x << "|" << std::setfill(' ') << std::setw(10) << std::dec << x << "|"; return ss.str(); } const char* audio_format_str(const uint16_t format) { if (format == FAUDIO_FORMAT_PCM) // 1 return "FAUDIO_FORMAT_PCM"; if (format == FAUDIO_FORMAT_MSADPCM) // 2 return "FAUDIO_FORMAT_MSADPCM"; if (format == FAUDIO_FORMAT_IEEE_FLOAT) // 3 return "FAUDIO_FORMAT_IEEE_FLOAT"; if (format == FAUDIO_FORMAT_WMAUDIO2) // 0x0161 return "FAUDIO_FORMAT_WMAUDIO2"; if (format == FAUDIO_FORMAT_WMAUDIO3) // 0x0162 return "FAUDIO_FORMAT_WMAUDIO3"; if (format == FAUDIO_FORMAT_WMAUDIO_LOSSLESS) // 0x0163 return "FAUDIO_FORMAT_WMAUDIO_LOSSLESS"; if (format == FAUDIO_FORMAT_XMAUDIO2) // 0x0166 return "FAUDIO_FORMAT_XMAUDIO2"; if (format == FAUDIO_FORMAT_EXTENSIBLE) // 0xFFE return "FAUDIO_FORMAT_"; return "FAUDIO_FORMAT_UNKNOWN"; } /* based on https://docs.microsoft.com/en-us/windows/desktop/xaudio2/how-to--load-audio-data-files-in-xaudio2 */ #define fourccRIFF *((uint32_t *) "RIFF") #define fourccDATA *((uint32_t *) "data") #define fourccFMT *((uint32_t *) "fmt ") #define fourccWAVE *((uint32_t *) "WAVE") #define fourccXWMA *((uint32_t *) "XWMA") #define fourccDPDS *((uint32_t *) "dpds") void print_sub_chunk(FILE *hFile, uint32_t &chunkID, uint32_t &dwChunkPosition) { /* data sub-chunk - 8 bytes + data */ uint32_t chunkSize; if (fread(&chunkID, sizeof(uint32_t), 1, hFile) < 1) { if (feof(hFile)) { std::cout << "reached end of file at: " << dwChunkPosition << std::endl; return; } throw std::runtime_error("can't read chunkID"); } dwChunkPosition += sizeof (uint32_t); if (chunkID == fourccDATA) { std::cout << "data chunk position: " << dwChunkPosition - sizeof(uint32_t) << std::endl; std::cout << "data: " << uint32_to_charstr(chunkID) << std::endl; if (fread(&chunkSize, sizeof(uint32_t), 1, hFile) < 1) throw std::runtime_error("can't read chunkSize"); dwChunkPosition += sizeof (uint32_t); std::cout << "data chunkSize: " << uint32_to_charstr(chunkSize) << std::endl; // skip the rest fseek(hFile, chunkSize, SEEK_CUR); dwChunkPosition += chunkSize; } else if (chunkID == fourccDPDS) { std::cout << "dpds chunk position: " << dwChunkPosition - sizeof(uint32_t) << std::endl; std::cout << "dpds: " << uint32_to_charstr(chunkID) << std::endl; if (fread(&chunkSize, sizeof(uint32_t), 1, hFile) < 1) throw std::runtime_error("can't read chunkSize"); dwChunkPosition += sizeof (uint32_t); std::cout << "dpds chunkSize: " << uint32_to_charstr(chunkSize) << std::endl; // skip the rest fseek(hFile, chunkSize, SEEK_CUR); dwChunkPosition += chunkSize; } else { std::cout << "unknown chunkID at position: " << dwChunkPosition - sizeof(uint32_t) << std::endl; std::cout << "unhandled chunk: " << uint32_to_charstr(chunkID) << std::endl; } } uint32_t load_data(const char *filename) { /* open the audio file */ FILE *hFile = fopen(filename, "rb"); if (!hFile) return 1; fseek(hFile, 0, SEEK_SET); uint32_t chunkID; uint32_t dwChunkPosition = 0; // search for 'RIFF' chunk bool foundRIFF = false; while (fread(&chunkID, sizeof(uint32_t), 1, hFile) > 0) { dwChunkPosition += sizeof (uint32_t); if (chunkID == fourccRIFF) { foundRIFF = true; std::cout << "found 'RIFF' at: " << dwChunkPosition - sizeof(uint32_t) << std::endl; break; } } if (!foundRIFF) { std::cout << "missing RIFF header" << std::endl; return 1; } { std::cout << "RIFF: " << uint32_to_charstr(chunkID) << std::endl; uint32_t filesize; uint32_t format; if (fread(&filesize, sizeof(uint32_t), 1, hFile) < 1) throw std::runtime_error("can't read RIFF filesize"); dwChunkPosition += sizeof (uint32_t); std::cout << "ChunkSize: " << uint32_to_charstr(filesize) << std::endl; if (fread(&format, sizeof(uint32_t), 1, hFile) < 1) throw std::runtime_error("can't read RIFF format"); dwChunkPosition += sizeof (uint32_t); std::cout << "Format: " << uint32_to_charstr(format) << std::endl; } uint32_t fmt_chunk_start = dwChunkPosition; uint32_t fmt_chunk_size = 0; { /* fmt sub-chunk 24 */ if (fread(&chunkID, sizeof(uint32_t), 1, hFile) < 1) throw std::runtime_error("can't read fmt chunkID"); dwChunkPosition += sizeof (uint32_t); std::cout << "fmt: " << uint32_to_charstr(chunkID) << std::endl; if (chunkID != fourccFMT) { std::cout << "expected chunkID 'fmt '" << std::endl; return 1; } if (fread(&fmt_chunk_size, sizeof(uint32_t), 1, hFile) < 1) throw std::runtime_error("can't read fmt chunkSize"); dwChunkPosition += sizeof (uint32_t); std::cout << "ChunkSize: " << uint32_to_charstr(fmt_chunk_size) << std::endl; uint16_t audio_format; if (fread(&audio_format, sizeof(uint16_t), 1, hFile) < 1) throw std::runtime_error("can't read fmt AudioFormat"); dwChunkPosition += sizeof (uint16_t); std::cout << "fmt AudioFormat: " << uint16_to_charstr(audio_format) << " " << audio_format_str(audio_format) << std::endl; uint16_t NumChannels; if (fread(&NumChannels, sizeof(uint16_t), 1, hFile) < 1) throw std::runtime_error("can't read fmt NumChannels"); dwChunkPosition += sizeof (uint16_t); std::cout << "fmt NumChannels: " << uint16_to_charstr(NumChannels) << std::endl; uint32_t SampleRate; if (fread(&SampleRate, sizeof(uint32_t), 1, hFile) < 1) throw std::runtime_error("can't read fmt SampleRate"); std::cout << "fmt SampleRate: " << uint32_to_charstr(SampleRate) << std::endl; uint32_t ByteRate; if (fread(&ByteRate, sizeof(uint32_t), 1, hFile) < 1) throw std::runtime_error("can't read fmt ByteRate"); dwChunkPosition += sizeof (uint32_t); std::cout << "fmt ByteRate: " << uint32_to_charstr(ByteRate) << std::endl; uint16_t BloackAlign; if (fread(&BloackAlign, sizeof(uint16_t), 1, hFile) < 1) throw std::runtime_error("can't read fmt BloackAlign"); dwChunkPosition += sizeof (uint16_t); std::cout << "fmt BloackAlign: " << uint16_to_charstr(BloackAlign) << std::endl; uint16_t BitsPerSample; if (fread(&BitsPerSample, sizeof(uint16_t), 1, hFile) < 1) throw std::runtime_error("can't read fmt BitsPerSample"); dwChunkPosition += sizeof (uint16_t); std::cout << "fmt BitsPerSample:" << uint16_to_charstr(BitsPerSample) << std::endl; } /* in case of extensible audio format write the additional data to the file */ if (fmt_chunk_size > 16) { std::cout << "fmt chunk position: " << dwChunkPosition - fmt_chunk_start << std::endl; uint16_t cb_size; if (fread(&cb_size, sizeof(uint16_t), 1, hFile) < 1) throw std::runtime_error("can't read fmt cbSize"); dwChunkPosition += sizeof (uint16_t); std::cout << "fmt cbSize: " << uint32_to_charstr(cb_size) << std::endl; if (cb_size >= 22) { uint16_t ValidBitsPerSample; if (fread(&ValidBitsPerSample, sizeof(uint16_t), 1, hFile) < 1) throw std::runtime_error("can't read fmt ex ValidBitsPerSample"); dwChunkPosition += sizeof (uint16_t); std::cout << "fmt ValidBitsPerS:" << uint16_to_charstr(ValidBitsPerSample) << std::endl; uint32_t dwChannelMask; if (fread(&dwChannelMask, sizeof(uint32_t), 1, hFile) < 1) throw std::runtime_error("can't read fmt ex dwChannelMask"); dwChunkPosition += sizeof (uint32_t); std::cout << "fmt dwChannelMask:" << uint32_to_charstr(dwChannelMask) << std::endl; uint32_t Data1; if (fread(&Data1, sizeof(uint32_t), 1, hFile) < 1) throw std::runtime_error("can't read fmt ex Data1"); dwChunkPosition += sizeof (uint32_t); std::cout << "fmt Data1: " << uint32_to_charstr(Data1) << std::endl; uint16_t Data2; if (fread(&Data2, sizeof(uint16_t), 1, hFile) < 1) throw std::runtime_error("can't read fmt ex Data2"); dwChunkPosition += sizeof (uint16_t); std::cout << "fmt Data2: " << uint16_to_charstr(Data2) << std::endl; uint16_t Data3; if (fread(&Data3, sizeof(uint16_t), 1, hFile) < 1) throw std::runtime_error("can't read fmt ex Data3"); dwChunkPosition += sizeof (uint16_t); std::cout << "fmt Data3: " << uint16_to_charstr(Data3) << std::endl; uint8_t Data4[8]; if (fread(&Data4, sizeof(uint8_t), 8, hFile) < 1) throw std::runtime_error("can't read fmt ex Data4"); dwChunkPosition += sizeof (uint8_t)*8; for (uint8_t i=0; i<8; i++) { std::cout << "fmt Data4["<(i)<<"]: " << uint8_to_charstr(Data4[i]) << std::endl; } uint16_t remaining_fmt_data = cb_size - 22; uint8_t dummy; std::cout << "fmt remaining data: " << remaining_fmt_data << std::endl; for (uint16_t i=0; i 22 std::cout << "fmt chunk position: " << dwChunkPosition - fmt_chunk_start << std::endl; } // ignore data until we find sub-chunk data if (!feof(hFile)) print_sub_chunk(hFile, chunkID, dwChunkPosition); if (!feof(hFile)) print_sub_chunk(hFile, chunkID, dwChunkPosition); return 0; } int main(int argc, char *argv[]) { /* process command line arguments. This is just a test program, didn't go too nuts with validation. */ if (argc < 2) { printf("Usage: %s filename\n", argv[0]); printf(" - filename (required): can be either a WAV or xWMA audio file.\n"); return -1; } if (load_data(argv[1]) != 0) { printf("Error loading data\n"); return -1; } printf("success\n"); return 0; }