Форум: "Media";
Текущий архив: 2008.03.16;
Скачать: [xml.tar.bz2];
ВнизПроблемы с размером полученного 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 вся ветка
Форум: "Media";
Текущий архив: 2008.03.16;
Скачать: [xml.tar.bz2];
Память: 0.51 MB
Время: 0.008 c