Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Заголовок wav файла [D5, Win95/98, WinXP]


Дмитрий (Гомель) ©   (2007-03-20 09:08:00) 

Итак, здравствуйте, друзья-программисты. Задача такова. Я имею несколько wav файлов одинакового формата PCM, 44100HZ, 16 bit... Собираю их в один файловый поток, предварительно убирая заголовки каждого (фрагмент кода взял из инета - каюсь), прописываю заголовок для полученного файла. Открываю для воспроизведения. И что? Winamp выдает "Invalid Fyle Type" Forge вообще может подвиснуть. Я так понимаю, что с заголовком что-то не так. Код будет через 6 часов выложен. Ваши мнения и поддержка? Кстати, уже благодарен господину Карапетяну за изложение струтуры wav файла. Но где-то собака порылась.


Дмитрий (Гомель)   (2007-03-23 08:40:00) [1]

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

unit Unit2;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
 StdCtrls, Grids, Calendar;

type
 TForm2 = class(TForm)
   Calendar1: TCalendar;
   Button1: TButton;
   Button2: TButton;
   Label1: TLabel;
   Label2: TLabel;
   procedure Button2Click(Sender: TObject);
   procedure FormShow(Sender: TObject);
   procedure Button1Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

 type
TWaveHeader = record
idRiff: array[0..3] of char;
RiffLen: longint;
idWave: array[0..3] of char;
idFmt: array[0..3] of char;
InfoLen: longint;
WaveType: smallint;
Ch: smallint;
Freq: longint;
BytesPerSec: longint;
align: smallint;
Bits: smallint;
idData:array[0..3] of char;
idDatalen:longint;
end;

var
 Form2: TForm2;

implementation

uses Unit1;

{$R *.DFM}

function GetWaveHeader(FileName: TFileStream): TWaveHeader;
const
riff = 'RIFF';
wave = 'WAVE';
var
w: TWaveHeader;
begin
FileName.Read(w, Sizeof(w));
if w.idRiff <> riff then
begin
Showmessage('This is not a RIFF File');
exit;
end;
if w.idWave <> wave then
begin
Showmessage('This is not a valid wave file');
exit;
end;
Result := w;
end;

procedure RenderBlocks(Den:integer);
const Modes: array[Boolean] of Word = (fmCreate, fmOpenReadWrite);
const
riff = 'RIFF';
wave = 'WAVE';
var
   i,ix:integer;
   long,L:longint;
   FName,FBlock,F: TFileStream;
   Name,NameBlock,ListFiles:String;
   w: TWaveHeader;
Begin {1}
Form1.Gauge1.MinValue:=0;
{Form1.ProgressBar1.Min:=0;}
Form1.Gauge1.MaxValue:=Form1.ListBox3.Items.Count;
Form1.Gauge1.Progress:=0;
{Form1.ProgressBar1.Max:=Form1.ListBox3.Items.Count;
Form1.ProgressBar1.Position:=0;}
for i:=1 to Form1.ListBox3.Items.Count do
begin {2}
if Form1.StringGrid1.Cells[Den,i]<>''
then
begin {3}
{Form1.ProgressBar1.Position:=Form1.ProgressBar1.Position+1;}
Form1.Gauge1.Progress:=Form1.Gauge1.Progress+ i;
{Создаем файлстрим на определенное время блока}
NameBlock:='';
NameBlock:='('+IntToStr(Den)+'.'+IntToStr(Form1.ComboBox2.Items.IndexOf(Form1.ComboBox2.Text)+1)+') '+Form1.StringGrid1.Cells[0,i]+'.wav';
FBlock := TFileStream.Create(NameBlock, Modes[FileExists(NameBlock)]);
F:=TFileStream.Create('temp.tmp', fmCreate);
try  {4}
FBlock.Seek(0, soFromEnd);
F.Seek(0, soFromEnd);
{Закончили создание файлстрима на определенное время блока}
ix:=0;
ListFiles:='';
ListFiles:=Form1.StringGrid1.Cells[Den,i];
long:=0;
L:=0;
while ix<=Length(ListFiles) do
begin {5}
if ListFiles[ix]='#'
then
begin {6}
Name:=TecDir+'\'+copy(ListFiles,1,ix-1)+'.wav';
Delete(ListFiles,1,ix);
ix:=0;
{!!}
FName:=TFileStream.Create(Name,fmOpenRead);
FName.Seek(0,soFromBeginning);
w := GetWaveHeader(FName);
long:=long+w.RiffLen;
L:=L+w.idDataLen;
Fname.Position:=SizeOf(w);
F.CopyFrom(FName,w.idDataLen);
FName.Free;
{!!}
end;  {6}
ix:=ix+1;
end; {5}
finally
F.Free;
w.RiffLen:=0;
w.idDataLen:=0;
w.RiffLen:=long;
w.idDataLen:=L;
FBlock.Seek(0,soFromBeginning);
FBlock.Write(w,SizeOf(w));
F:=TFileStream.Create('temp.tmp', fmOpenRead);
FBlock.copyfrom(F,F.Size);
FBlock.Free;
F.Free;
DeleteFile('temp.tmp')
end;  {4}
end; {3}
end;{2}
Form1.Gauge1.Progress:=Form1.Gauge1.MaxValue;
{Form1.ProgressBar1.Position:=Form1.ProgressBar1.Max;
Form1.ProgressBar1.Position:=Form1.ProgressBar1.Min;}
end;{1}

procedure TForm2.Button2Click(Sender: TObject);
begin
Form2.Close;
end;

procedure TForm2.FormShow(Sender: TObject);
begin
Button1.SetFocus;
end;

procedure TForm2.Button1Click(Sender: TObject);
var
       d:integer;
begin
d:=0;
d:=Calendar1.Day;
Form2.Hide;
Form2.Close;
RenderBlocks(D);
end;

end.


wicked   (2007-03-22 12:19:00) [2]

> Дмитрий (Гомель)   (22.03.07 07:56) [6]
удачи и попутного ветра.... :)


Дмитрий (Гомель)   (2007-03-22 07:56:00) [3]

А теперь ответ для особо "ленивых". Эта запись представляет собой структуру заголовка wav-файла. Причем эта вся вещь теперь работает. Я разобрался. Остальным советую читать доки. Опять же опираюсь на статьи господина Карапетяна, который внятно и доступно изложил все понятия. Весь листинг программы приведу чуть позже. Исправил баги, и склеиваю файлы вместе не два и не три, а то и больше. Причем это я сделал без API. И этим горжусь. Всем удачи... Ждите продолжения.


wicked   (2007-03-21 16:10:00) [4]

код весь не читал - лениво вглядываться в плохо отформатированный текст...
но после вот этого маразма

> TWaveHeader = record
> idRiff: array[0..3] of char;
> RiffLen: longint;
> idWave: array[0..3] of char;
> idFmt: array[0..3] of char;
> {InfoLen: longint;}
> WaveType: smallint;
> Ch: smallint;
> Freq: longint;
> BytesPerSec: longint;
> align: smallint;
> Bits: smallint;
> idData:array[0..3] of char;
> end;

есть мнение - источник, это выдавший, не имеет права на доверие - это НЕ ЗАГОЛОВОК wav.... это несколько заголовков, склеенных в кучу, причем между ними могут быть еще данные
поэтому, я бы не советовал пользоваться примерами из того же источника - они заведомо неправильные

см. также сюда - http://www.delphimaster.ru/cgi-bin/forum.pl?id=1173158554&n=7&from=5


Дмитрий (Гомель)   (2007-03-21 08:50:00) [5]

Ну вот. Ваше мнение? Может еще какой-то параметр нужно изменять. Например, InfoLen...?


Дмитрий (Гомель)   (2007-03-21 08:08:00) [6]

Полностью согласен с предыдущими ответами. Однако, склеивая два файла в один, я получаю при проигрывании все равно первый. Файл в размерах как на два, а играет один. Даю фрагмент кода, но сразу оговариваюсь, что "да, я в самом начале в поток прописываю заголовок, но учитываю длину двух файлов, например длина одного 1431344, другого 2855845, то в итоге просто записал сумму, при остальных одинаковых параметрах, может где еще собака порылась". Вот код...:
....

type
TWaveHeader = record
idRiff: array[0..3] of char;
RiffLen: longint;
idWave: array[0..3] of char;
idFmt: array[0..3] of char;
{InfoLen: longint;}
WaveType: smallint;
Ch: smallint;
Freq: longint;
BytesPerSec: longint;
align: smallint;
Bits: smallint;
idData:array[0..3] of char;
end;
{
TDataHeader = record
idData: array[0..3] of char;
DataLen: longint;
end;}

var
 Form2: TForm2;

implementation

uses Unit1;

{$R *.DFM}

function GetWaveHeader(FileName: TFileStream): TWaveHeader;
const
riff = 'RIFF';
wave = 'WAVE';
var
w: TWaveHeader;
begin
FileName.Read(w, Sizeof(w));
if w.idRiff <> riff then
begin
Showmessage('This is not a RIFF File');
exit;
end;
if w.idWave <> wave then
begin
Showmessage('This is not a valid wave file');
exit;
end;
Result := w;
end;

procedure RenderBlocks(Den:integer);
const Modes: array[Boolean] of Word = (fmCreate, fmOpenReadWrite);
const
riff = 'RIFF';
wave = 'WAVE';
var
   i,ix,k,p:integer;
   long,long1:longint;
   FName,FBlock,F: TFileStream;
   DataSize : DWord;
   Name,NameBlock,NameBlock1,ListFiles:String;
   w,zw: TWaveHeader;

Begin {1}
FBlock := TFileStream.Create(NameBlock, Modes[FileExists(NameBlock)]);
try  {4}
FBlock.Seek(0, soFromEnd);
FName:=TFileStream.Create(Name,fmOpenRead);
FName.Seek(0,soFromBeginning);
w := GetWaveHeader(FName);
long:=long+w.RiffLen;
w.RiffLen:=0;
w.RiffLen:=long;{вот здесь и пишу сумму, может надо еще что-то суммировать?}
Fname.Position:=SizeOf(w);
FBlock.Write(w,SizeOf(w));
FBlock.CopyFrom(FName,FName.Size-SizeOf(w));
FName.Free;
{!!}
end;  {6}
ix:=ix+1;
end; {5}
finally
w.RiffLen:=0;
w.RiffLen:=long;
FBlock.Free;
{F.Free;                    }
end;  {4}
end; {3}
end;{2}
end;{1}


TRUNK   (2007-03-20 21:11:00) [7]

> [0] Дмитрий (Гомель)   (20.03.07 09:08)
>Код будет через 6 часов выложен

А где он будет выложен?

> [1] toboom ©   (20.03.07 16:29)
>нужно добавлять и длину результирующего файла

Как таковая, длина файла в заголовке отсутствует. Вместо неё там есть два значения, взаимосвязанных с ней:
1) размер RIFF, меньше или равен FileSize-8;
2) размер звуковых данных, меньше или равен FileSize-44.


toboom   (2007-03-20 16:29:00) [8]

Судя по выдаваемому сообщению дело именно в заголовке.
В него, наск. я помню, нужно добавлять и длину результирующего файла.
Может ещё какая беда. Но думаю, что именно в заголовке.


Наверх

Титульная страница Поиск, карта сайта Написать письмо