Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2008.03.16;
Скачать: CL | DM;

Вниз

Проблемы с размером полученного wav   Найти похожие ветки 

 
Дмитрий (Гомель)   (2007-03-28 11:06) [0]

Итак, здравствуйте, господа-программисты. Совсем недавно решил при помощи инета задачу склеить несколько wav-файлов в один. Уже в конференции по Media об этом сообщал. Однако возникла проблема. Если, например файл из формата МР-2 перегоняют в wav, то при склеивании этого файла (даже если он один в блоке склеивания), при формировании заголовка и самого файла почему-то не сходится размер. Он меньше исходного на 34 байта по-моему. Точно надо посмотреть. Причем, есть подозрение, что не все прочитывается в заголовке wav-файла. У кого были похожие вопросы? Был бы благодарен за консультативную информацию.


 
wicked ©   (2007-03-28 11:59) [1]

а что говорит про это г-н Карапетян?


 
homm ©   (2007-03-28 12:03) [2]

> Он меньше исходного на 34 байта по-моему

Размер заголовка?


 
TRUNK ©   (2007-03-28 12:12) [3]

Это всё из-за того, что некорректно обрабатывется структура файла. Долго наблюдал за соседней веткой (какой именно - думаю говорить не стоит), но так никто ничего и не поправил. Похоже, что придётся это сделать мне :). Во-первых, заголовки в RIFF файле читать надо по-отдельности, а не одним блоком, т.к. не факт, что они будут идти именно в такой последовательности. Во-вторых, размер RiffLen для конечного файла определяется некорректно. В-третьих, в файле могут быть и другие секции данных, которые тоже нужно учитывать.


 
wicked ©   (2007-03-28 12:18) [4]

> TRUNK ©   (28.03.07 12:12) [3]
поправил...
только вместо рыбы я дал человеку удочку

отсюда и мой первый постинг - пусть ответит на вопрос :)


 
wicked ©   (2007-03-28 12:22) [5]

добавлю, что WAVEFORMATEX очень часто бывает частью другого заголовка
какого именно - определяется полями wFormatTag и cbSize

но подождем, что скажет г-н Карапетян ;)


 
TRUNK ©   (2007-03-28 12:32) [6]

> wicked ©   (28.03.07 12:22) [5]
> но подождем, что скажет г-н Карапетян ;)

Может я чего недочитал, но если не секрет, кто такой Карапетян ?


 
wicked ©   (2007-03-28 12:42) [7]

> TRUNK ©   (28.03.07 12:32) [6]

>
> > wicked ©   (28.03.07 12:22) [5]
> > но подождем, что скажет г-н Карапетян ;)
>
> Может я чего недочитал, но если не секрет, кто такой Карапетян
> ?

упоминается он там - http://delphimaster.net/view/8-1174370882/

а кто он?... не знаю, авторитет какой то, у автора надо спрашивать :)


 
Дмитрий (Гомель)   (2007-03-29 11:50) [8]

Привет, народ! Ну навалились все разом! Ладно уже распинать :-). Ну бывают траблы. Кто ничего не делает - тот и не ошибается. Согласен. Обработку заголовка файла вел лишь по определенной схеме. Каких-то вещей не знаю. Скребу инет в поисках "утраченного". Про авторитет - человек предложил схему, я ее использовал. Работало. Теперь получил другие файлы. Увы... Вот и вопрос. Как мне обработать все заголовки, заранее не зная в какой они идут последовательности. Тема для меня все-таки новая, но разобраться хочу. Размер Rifflen? Уже согласен. Определяется не так как в первый раз (в исходном коде). Как учесть другие секции данных? Каков метод?


 
TRUNK ©   (2007-03-29 14:07) [9]

На первый и третий вопросы (Как обработать все заголовки и Как учесть другие секции данных) одно решение - при их поиске пользоваться именами, находящимися в заголовках секций (те самые "fmt " и "data"). Другими словами, нужно прочитать имя первой секции и её размер. Если имя секции не то которое нас интересует или вообще неизвестное, увеличиваем файловый указатель на размер секции, тем самым переходя на начало следующей секции (либо в конец файла). Если же имя подходит - читаем данные из этой секции. Далее повторяем тоже самое пока не будут найдены все интересующие данные. Алгоритм очень простой. Что же касается Rifflen, то, в подавляющем большинстве случаев, она равна FileSize-8.


 
Дмитрий (Гомель)   (2007-03-29 17:15) [10]

Ок. Таким образом мы переходим к следующей ступени. Я ищу скажем так ключевые слова: Wave, Riff, fmt, data. Тогда вопрос, каков размер каждой секции? Секции имеют фиксированный размер?Т.е. я понимаю ситуация такова - я начинаю читать файл по байтам или по фиксированному размеру, например 4? чтобы попасть в нужный размер? что есть точка отсчета? хотя мне кажется я уже понимаю.


 
wicked ©   (2007-03-29 17:24) [11]

повторю еще раз - взяться и почитать об mmioOpen/mmioClose, mmioAscend/mmioDescend, mmioRead/mmioWrite - все уже написано и не надо "искать ключевые слова"


 
Дмитрий (Гомель)   (2007-03-29 17:34) [12]

Ну что же, я почитаю обязательно. А чем это интереснее? потому что API? Если где-то ошибся прошу извинить.


 
TRUNK ©   (2007-03-30 10:23) [13]

> Дмитрий (Гомель)   (29.03.07 17:15) [10]

Секция устроена так: сначала идут 4 байта с именем, затем 4 байта с размером данных, затем идут данные этой секции, т.е. условно так:
ChunkName: array[0..3] of Char;
ChunkSize: Cardinal;
ChunkData: ...; // размер равен ChunkSize
Размер всей секции, следовательно, равен ChunkSize+8.
Существует ещё один вид секций - это секции-контейнеры, которые могут содержать в себе другие секции. Таких секций-контейнеров пока всего два вида - это LIST и RIFF. Их формат отличается тем, что первые четыре байта данных указывают тип содержимого секции-контейнера. Например, в нашем случае у секции RIFF тип содержимого WAVE.

> Я ищу скажем так ключевые слова: Wave, Riff, fmt, data

Как, наверное, уже стало понятно, WAVE искать не надо - его надо проверять. RIFF искать тоже не надо - нужно просто в самом начале проверить, что первые четыре байта файла равны RIFF. Искать в нашем случае надо только fmt и data.

P.S. Если всё-равно будет непонятно, могу кинуть на мыло пример объединения WAV-файлов.


 
Дмитрий (Гомель)   (2007-03-30 17:15) [14]

Спасибо, TRUNK. Пока сам поковыряю. Если можно - буду по мере формирования кода демонстрировать в ветке? Комментарии конечно будут нужны. Главное что стало понятно следующее - непостоянная структура wav. Ну извините, что так? Спасибо, парни. Еще появлюсь.


 
Дмитрий (Гомель)   (2007-04-13 18:58) [15]

Привет, народ. Вот я и появился вновь. Все работает - склеивает файлы PCM формата 16 Bit и с частотой 44100. Вот код чтения:

function ReadWaveHeader(FileName:String;F:TFileStream):TWaveHeader;
var
    WaveHeader:TWaveHeader;
    DataChunk:      String[4];
    Name:           TFileStream;
    Pos:            Integer;
    Data:           PChar;
    DataSize:       DWord;
{     ChunkID:        Array[0..3] of Char; {метка "RIFF"}
{     ChunkIDSize:    LongInt;             {размер "Rifflen"}
{     FormatPCM:      Array[0..3] of Char; {метка "WAVE"}
{     SubChunk1ID:    Array[0..3] of Char; {метка "fmt_"}
{     SubChunk1IDSize:LongInt;             {размер "fmt_"}
{     AudioFormatPCM: Word;                {метка формата PCM, если "1", то все в порядке}
{     NumChannels:    Word;                {количество каналов, 2 - стерео, 1-моно}
{     SampleRate:     LongInt;             {частота - 44100 Гц}
{     BytesPerSecond: LongInt;             {}
{     BlockAlign:     Word;                {}
{     BitsPerSample:  Word;                {16 bit}
{     SubChunk2ID:    Array[0..3] of Char; {метка "data"}
{    SubChunk2Size:  LongInt;      }

begin
Name:=TFileStream.Create(FileName,fmOpenRead);
Pos:=0;
SetLength(DataChunk,4);
repeat
 Name.Seek(Pos, soFromBeginning);
 Name.Read(DataChunk[1],4);
 if DataChunk="RIFF" then
 begin
 WaveHeader.ChunkID:="RIFF";
 Name.Read(WaveHeader.ChunkIDSize,4);
 end;
 if DataChunk="WAVE" then
 begin
 WaveHeader.FormatPCM:="WAVE";
 end;
 if DataChunk="fmt " then
 begin
 WaveHeader.SubChunk1ID:="fmt ";
 Name.Read(WaveHeader.SubChunk1IDSize,4);
 Name.Read(WaveHeader.AudioFormatPCM,2);
 Name.Read(WaveHeader.NumChannels,2);
 Name.Read(WaveHeader.SampleRate,4);
 end;
 Inc(Pos);
until DataChunk = "data";
if (WaveHeader.ChunkID<>"RIFF") or (WaveHeader.FormatPCM<>"WAVE") or (WaveHeader.SubChunk1ID<>"fmt ") or (WaveHeader.AudioFormatPCM<>1)
then
showmessage("Invalid wav-mediafile");
WaveHeader.SubChunk2ID:="data";
Name.Read(WaveHeader.SubChunk2Size,4);
Pos:=Name.Position;
Name.Seek(Pos-4,soFromBeginning);
Name.Read(DataSize, Sizeof(DWORD));
GetMem(Data,DataSize);
Name.Read(Data^,DataSize);
F.Seek(0,soFromEnd);
F.Write(Data^,DataSize);
FreeMem(Data,DataSize);
Name.Free;
Result:=WaveHeader;
end;

Несколько комментариев. Я читаю заголовок, отделяю тело и получаю готовый материал.

Процедура формирования заголовка и итогового файла такова:

procedure CreateWaveHeader(FTemp:String;FB:TFileStream);
var
MF:TFileStream;
begin
MF:=TFileStream.Create(FTemp,fmOpenRead);
WaveF.ChunkID:="RIFF";
WaveF.ChunkIDSize:=MF.Size+36;
WaveF.FormatPCM:="WAVE";
WaveF.SubChunk1ID:="fmt ";
WaveF.SubChunk1IDSize:=16;
WaveF.AudioFormatPCM:=1;
WaveF.NumChannels:=2;
WaveF.SampleRate:=44100;
WaveF.BytesPerSecond:=WaveF.SampleRate*WaveF.NumChannels;
WaveF.BitsPerSample:=16;
WaveF.SubChunk2ID:="data";
WaveF.SubChunk2Size:=MF.Size;
FB.Write(waveF,sizeof(waveF));
FB.copyfrom(MF,MF.Size);
MF.Free;
.......

Полученные файлы читаются, играются. В общем все четко. Но один нюанс. При перегоне формата моего полученного файла в другой в старый формат MP-2 (кодек QDesign) выскакивает сообщение "Ошибка инициализации аудио обработки". Что я не дописываю в файл или что делаю неверно? Заранее спасибо.


 
TRUNK ©   (2007-04-16 15:41) [16]

Создание заголовка надо изменить так:

//...........................
WaveF.AudioFormatPCM := 1;
WaveF.NumChannels := 2;
WaveF.SampleRate := 44100;
WaveF.BitsPerSample := 16;
WaveF.BlockAlign := (WaveF.BitsPerSample div 8)*WaveF.NumChannels;
WaveF.BytesPerSecond := WaveF.SampleRate*WaveF.BlockAlign;
//...........................


 
Дмитрий (Гомель)   (2007-04-21 11:22) [17]

TRUNK. Спасибо. Вот залез на ветку опять - не оставили без внимания. Но сам уже разобрался. Немного невнимателен был. Все получилось. Отлично. Теперь думаю, как конвертер написать для других файлов, например с другой частоткой (48 kHZ, mp3 и т.д.). Соответственно кодек использовать для этого Lame (как вариант). В какую сторону копать? Т.е. я хочу, чтобы программа детектила файл, определяла его формат и сама конвертила в простой PCM?



Страницы: 1 вся ветка

Текущий архив: 2008.03.16;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.013 c
2-1203100055
operator
2008-02-15 21:27
2008.03.16
Как поменять местами node-ы в treeview?


2-1203005847
Ega23
2008-02-14 19:17
2008.03.16
CreateProcess - флаги


3-1193343940
dik
2007-10-26 00:25
2008.03.16
Работа с Blob


2-1203493920
Александр
2008-02-20 10:52
2008.03.16
Excel в OleContainer


2-1203439928
Рустам
2008-02-19 19:52
2008.03.16
корректное отображение в базе данных