Юзаю такой код:
struct WAVHEADER { // WAV-формат начинается с RIFF-заголовка: // Содержит символы "RIFF" в ASCII кодировке // (0x52494646 в big-endian представлении) char chunkId[4]; // 36 + subchunk2Size, или более точно: // 4 + (8 + subchunk1Size) + (8 + subchunk2Size) // Это оставшийся размер цепочки, начиная с этой позиции. // Иначе говоря, это размер файла - 8, то есть, // исключены поля chunkId и chunkSize. unsigned long chunkSize; // Содержит символы "WAVE" // (0x57415645 в big-endian представлении) char format[4]; // Формат "WAVE" состоит из двух подцепочек: "fmt " и "data": // Подцепочка "fmt " описывает формат звуковых данных: // Содержит символы "fmt " // (0x666d7420 в big-endian представлении) char subchunk1Id[4]; // 16 для формата PCM. // Это оставшийся размер подцепочки, начиная с этой позиции. unsigned long subchunk1Size; // Аудио формат, полный список можно получить здесь http://audiocoding.ru/wav_formats.txt // Для PCM = 1 (то есть, Линейное квантование). // Значения, отличающиеся от 1, обозначают некоторый формат сжатия. unsigned short audioFormat; // Количество каналов. Моно = 1, Стерео = 2 и т.д. unsigned short numChannels; // Частота дискретизации. 8000 Гц, 44100 Гц и т.д. unsigned long sampleRate; // sampleRate * numChannels * bitsPerSample/8 unsigned long byteRate; // numChannels * bitsPerSample/8 // Количество байт для одного сэмпла, включая все каналы. unsigned short blockAlign; // Так называемая "глубиная" или точность звучания. 8 бит, 16 бит и т.д. unsigned short bitsPerSample; // Подцепочка "data" содержит аудио-данные и их размер. // Содержит символы "data" // (0x64617461 в big-endian представлении) char subchunk2Id[4]; // numSamples * numChannels * bitsPerSample/8 // Количество байт в области данных. unsigned long subchunk2Size; // Далее следуют непосредственно Wav данные. }; FILE* file_; errno_t err; err = fopen_s(&file_, "content//konga.wav", "rb"); if ( err) { printf_s( "Failed open file, error %d", err); return 0; } WAVHEADER header; fread_s( &header, sizeof( WAVHEADER), sizeof( WAVHEADER), 1, file_); printf( "audioformat:%d\n", header.audioFormat); printf( "bitsPerSample:%d\n", header.bitsPerSample); printf( "blockAlign:%d\n", header.blockAlign); printf( "byteRate:%lu\n", header.byteRate); printf( "chunkId:%s\n", header.chunkId); printf( "chunkSize:%lu\n", header.chunkSize); printf( "format:%s\n", header.format); printf( "numCannels:%d\n", header.numChannels); printf( "sampleRate:%lu\n", header.sampleRate); printf( "subchunk1Id:%s\n", header.subchunk1Id); printf( "subchunk1Size:%lu\n", header.subchunk1Size); printf( "subchunk2Id:%s\n", header.subchunk2Id); printf( "subchunk2Size:%lu\n", header.subchunk2Size); fclose( file_);
Выхлоп такой в случае хорошего файла https://ibb.co/Rv8hJKZ И в моем случае https://ibb.co/dgBg4Fh
сам звук тут https://wav-library.net/afrikanskij-konga-baraban-muzykalnaya-pod… zhka-zvuk-mp3 транслированный в wav на одном из сайтов https://audio.online-convert.com/ru/convert-to-wav
Не понял вопроса (его и не было, было лишь повествование истории), но с помощью телепатии попробую предположить, что может быть не так.
RIFF-файлы (частным случаем которых являются WAV-файлы) - это файлы не фиксированного формата, а наборы вложенных (в общем случае) chunk-ов, типа конвертов в конвертах. Все chunk-и имеют реально только два поля заголовка - chunkId (четырехбуквенный индентификатор, иначе называемый FOURCC) и поле длины chunk-а. Дальше с точки зрения этого chunk-а - произвольное содержимое, зависящее от типа chunk-а. Chunk-и типа RIFF (самый внешний chunk) и LIST фактически содержат в себе один или подряд несколько вложенных chunk-ов.
В твоей программе "хедер" фактически подразумевающий лишь внешний chunk "RIFF" и один вложенный в него chunk "WAVE", который в свою очередь содержит два вложенных chunk-а "fmt " и "data":
RIFF ( WAVE ( fmt ( формат данных ) data ( сами данные ) ) )
А судя по полученному тобой выводу, в случае имеющегося у тебя файла в нем вместо просто одного вложенного chunk-а data у тебя chunk LIST, в котором может лежать еще несколько chunk-в.
RIFF ( WAVE ( fmt ( формат данных ) LIST ( тут хрен знает что вложено ) ) )
Конкретное содержимое LIST надо разбирать путем последовательного прохода по всем чанкам внутри (т.к. тебе известна суммарная длина LIST в байтах и длины вложенных chunk-ов).
Если ты работаешь в Windows, то в WinAPI есть наборы специальных функций для работы с такой chunk-овой структурой riff-файлов, например, mmioDescend
Да, вот еще обратил внимание, что у тебя длина chunk-а RIFF офигенная, а длины chunk-ов fmt и LIST - маленькие, то есть после chunk-а LIST у тебя еще какие-то chunk-и вложены во внешний RIFF
RIFF ( WAVE ( fmt ( формат данных ) LIST ( тут хрен знает что вложено ) ЕЩЕК акие-то чанки ... ) )
Решил конвертированием файла такой командой
ffmpeg -i konga.mp3 -map_metadata -1 -fflags +bitexact konga.wav
На всякий случай освежил данные по RIFF, а то давно дело было. Оказалось, память меня немного подвела, неточно я указал выше. WAVE это сам по себе не chunk, это спецификация chunk-а-контейнера. (то есть у chunk-ов RIFF и LIST сразу после длины идет еще оддин FOURCC, который просто уточняет тип RIFF-а или LIST-а).
То есть правильно рассматривать вот так
RIFF(WAVE) { fmt { формат данных } LIST(смотри FOURCC после поля его длины) { тут хрен знает что вложено } ЕЩЕК акие-то чанки (скорее всего data) ... }
Beginerok
> Решил конвертированием файла такой командой
В общем случае это не решение. В любой момент тебе может прилететь WAVE с отличающейся внутренней структурой. Правильно парсить WAV не твоим длинным фиксированным хедером, а спускаться по иерархии чанков, конкретно, если тебе интересны только формат и звуковые данные (а всякие тексты, субтитры, метаинфо неинтересны) - то тебе внутри chunk-а RIFF надо искать только chunk-и "fmt " и "data", и парсить именно их.
Если ты знаешь что там внутри mp3-упаковка, можно проще сделать - вообще наплевать на структуру, никакие заголовки не парсить, а сразу искать сигнатуру начала mp3. Все лишнее будет автоматически пропущено.
Dmitry_Milk
Так ты мне объясни нормально структуру его и я и пропущу или напишу нормальную структуру для его чтения, на всех сайтах бред, на википедии вообще объяснение хуже твоего
Beginerok
> fread_s(&header, sizeof(WAVHEADER), sizeof(WAVHEADER), 1, file_);
Сразу фейл.
Beginerok
> Так ты мне объясни нормально структуру
Ок. Попытаюсь еще раз.
В wav-файле (как и других riff-файлах) НЕТ одного заголовка фиксированного формата. Его нельзя рассматривать как "в начале заголовок потом содержимое".
riff-файлы состоят из так называемых чанков (chunk), часто вложенных друг в друга. Вот у каждого чанка ЕСТЬ фиксировнный заголовок, и этот заголовок состоит всего из двух полей - тип чанка (chunkID, 4 char-а) и длина содержимого чанка (32-битный int). После заголовка чанка следует его содержимое указанной длины.
Что именно будет представлять из себя содержимое конкретного чанка - определяется его chunkId.
Например, в чанке "fmt " находится структура
А в чанке "data" находятся сами аудиоданные
Особые типы чанков, RIFF и LIST, являются контейнерами для других чанков, и в своем содержимом содержат спецификатор подтипа (ниже обозначено listType, 4 char-а ) и подряд за ним один или несколько других чанков.
+==========================+ + chunkId = "RIFF" + +--------------------------+ + size + +--------------------------+ + + listType = "WAVE" + + +======================+ + + chunkId = "fmt " + + +----------------------+ + + size = 16 + + +----------------------+ + + + audioFormat + + + +------------------+ + + + numChannels + + + +------------------+ + + + sampleRate + + + +------------------+ + + + byteRate + + + +------------------+ + + + blockAlign + + + +------------------+ + + + bitsPerSample + + +======================+ + + chunkId = "LIST" + + +----------------------+ + + size + + +----------------------+ + + + listType + + + +==================+ + + + chunkId + + + +------------------+ + + + size + + + +------------------+ + + + ... + + + + ... + + + +==================+ + + + chunkId + + + +------------------+ + + + size + + + +------------------+ + + + ... + + + + ... + + + +==================+ + + + ... + + +======================+ + + chunkId = "data" + + +----------------------+ + + size + + +----------------------+ + + аудио + + + данные + + +======================+ + + chunkId + + +----------------------+ + + size + + +----------------------+ + + ... + + +======================+ + + chunkId + + +----------------------+ + + size + + +----------------------+ + + ... + + +======================+ + + ... + +==========================+
Вот я изобразил файл, в котором в корневом чанке RIFF лежат 5 или более вложенных чанков. Тебе надо среди них найти чанки fmt и data. При этом ты должен понимать, что последовательность этих чанков теоретически может быть любой. Скажем, в первом твоем файле чанки fmt и data шли подряд, а вот во втором - сначала шел чанк fmt а за ним чанк LIST. Какие чанки там лежали дальше мы не знаем, для этого ты должен идти по цепочке чанков, перескакивая их содержимое (а для этого тебе как раз и нужно поле size у каждого чанка).
Предлагаю бомжевание.
Но если пока ещё не хочется, могу предложить и такой вариант - не пытаться распарсить все варианты одним велосипедом, а скачать с интернета готовую библиотеку. Например, у себя я решил читать аудио через libFLAC.
Если же всё-таки хочется всё самому - то имеет смысл скачать спецификацию и делать по ней, тогда вот вот таких вот неожиданностей быть не должно.
Но лучше скачать готовую библиотеку.
Тема в архиве.