![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#31
|
||||
|
||||
|
Ночью заниматься этим лень, днём перепишу.
|
|
#32
|
|||
|
|||
|
Цитата:
|
|
#33
|
|||||
|
|||||
|
Цитата:
Цитата:
Цитата:
Цитата:
Для звука, обычно по оси OX (по абсциссе) откладывается время, а по оси OY (по ординате) откладывается амплитуда звука. Я сделал небольшой пример (смотри во вложении), он рисует волну так, как на рисунке angvelem сверху. А вот снизу слева на этом рисунке, это уже амплитудно-частотный график (эквалайзер), там уже скорее всего не обошлось без быстрого преобразования Фурье. Такого я никогда не делал, так что если тебе нужен именно такой график, то прийдётся подождать когда angvelem переведёт код с ассемблера на Delphi. Цитата:
|
| Этот пользователь сказал Спасибо poli-smen за это полезное сообщение: | ||
Dmitry_DM (29.08.2012)
| ||
|
#34
|
|||
|
|||
|
Цитата:
|
|
#35
|
||||
|
||||
|
вот тут все рисуется есть исходник, там и класс, обеспечивающий БПФ
|
|
#36
|
|||
|
|||
|
Я интегрировал пример от poli-smen в свою программу. Так сказать, удалось. Но так же, как и бар громкости (может кто помнит тему про муз. плеер), бар, который увеличивает масштаб гистограммы и волны, начинает работать при одном любом нажатии на него. Так же было и с баром громкости. Два раза совпасть не может. Это не в коде дело. Может это из-за трек бара от AlphaControl?
|
|
#37
|
||||
|
||||
|
Обновил вложение.
|
|
#38
|
|||
|
|||
|
poli-smen, я все сделал и у меня все работает, как я хотел. Но в то время пока я занимался медиаплеером и графиками, (по чистой случайности заметил), перестала работать ЗАПИСЬ нового wav. Причину я, скорее всего, вычислил. Это идентификатор NumSamples. Он стал находится в
Код:
TWavInfo = record
WaveFormat: TWaveFormat;
NumSamples: Integer;
MaxAmplitude: Integer;
Samples: packed array of array of Smallint;
end;Я так понял это нужно для построения графика. Но перестала работать запись, просто кнопка не работает. Я заметил в процедуре чтения эту новую строчку: Код:
WavInfo.NumSamples := LongInt(NumSamples); Код:
procedure WriteWav(const FileName: string; const WavInfo: TWavInfo);
type
TChunkID = packed array[0..3] of Char;
THeader = packed record
ChunkID: TChunkID;
ChunkSize: Longword;
Format: TChunkID;
Subchunk1ID: TChunkID;
Subchunk1Size: Longword;
AudioFormat: Word;
NumChannels: Word;
SampleRate: Longword;
ByteRate: Longword;
BlockAlign: Word;
BitsPerSample: Word;
Subchunk2ID: TChunkID;
Subchunk2Size: Longword;
end;
var
Header: THeader;
NumSamples, BytsPerSample, I, J: Longword;
fs: TFileStream;
begin
NumSamples := LongInt(NumSamples); //это я изменил, думал поможет, нет!
BytsPerSample := WavInfo.WaveFormat.wBitsPerSample div 8;
Header.ChunkID := 'RIFF';
Header.Format := 'WAVE';
Header.Subchunk1ID := 'fmt ';
Header.Subchunk1Size := 16;
Header.AudioFormat := WAVE_FORMAT_PCM;
Header.NumChannels := WavInfo.WaveFormat.nChannels;
Header.SampleRate := WavInfo.WaveFormat.nSamplesPerSec;
Header.BitsPerSample := BytsPerSample * 8;
Header.BlockAlign := Header.NumChannels * BytsPerSample;
Header.ByteRate := Header.SampleRate * Header.BlockAlign;
Header.Subchunk2ID := 'data';
Header.Subchunk2Size := NumSamples * Header.BlockAlign;
Header.ChunkSize := Header.Subchunk2Size + SizeOf(Header) - 8;
fs := TFileStream.Create(FileName, fmCreate);
try
fs.WriteBuffer(Header, SizeOf(Header));
for I := 1 to NumSamples do
begin
for J := 1 to Header.NumChannels do
begin
fs.WriteBuffer(WavInfo.Samples[I - 1, J - 1], BytsPerSample);
end;
end;
finally
fs.Free;
end;
end;
procedure TForm1.Button4Click{это кнопка записи}(Sender: TObject);
begin
if WavInfo.WaveFormat.wFormatTag = WAVE_FORMAT_PCM then
begin
if SaveDialog2.Execute then
begin
WriteWav(SaveDialog2.FileName, WavInfo);
end;
end;
end;А еще меня все время интересовал вопрос: что выполняет эта строчка в процедуре чтения? Код:
SetLength(WavInfo.Samples, WavInfo.WaveFormat.nChannels, NumSamples); Последний раз редактировалось Dmitry_DM, 30.08.2012 в 20:29. |
|
#39
|
||||
|
||||
|
Цитата:
P.S. Пример на Дельфи не вдохновил? Последний раз редактировалось angvelem, 30.08.2012 в 21:31. |
| Этот пользователь сказал Спасибо angvelem за это полезное сообщение: | ||
Dmitry_DM (30.08.2012)
| ||
|
#40
|
||||
|
||||
|
Может нужно
Код:
NumSamples := LongInt(WavInfo.NumSamples); |
|
#41
|
||||
|
||||
|
Цитата:
Самое главное изменение это то, что в массиве Samples поменялись местами размерности. Это изменение связано с особенностью реализации динамических массивов в Delphi, а именно то что: Код:
SetLength(Samples, 10000000, 2); // такая команда съест значительно больше памяти SetLength(Samples, 2, 10000000); // чем такая Код:
NumSamples := Length(WavInfo.Samples); Код:
NumSamples := WavInfo.NumSamples; Код:
// Т.е. вместо: fs.WriteBuffer(WavInfo.Samples[I - 1, J - 1], BytsPerSample); // нужно писать так: fs.WriteBuffer(WavInfo.Samples[J - 1, I - 1], BytsPerSample); Цитата:
В программе рисования звуковой волны процедура сохранения была не нужна, поэтому её я не переделывал (и не использовал), но теперь у тебя есть вся информация для её переделки. ![]() |
| Этот пользователь сказал Спасибо poli-smen за это полезное сообщение: | ||
Dmitry_DM (31.08.2012)
| ||
|
#42
|
|||
|
|||
|
Ошибки я все исправил. Про которые вы писали. Кнопка все равно не нажимается, потому что не проходит
Код:
if WavInfo.WaveFormat.wFormatTag = WAVE_FORMAT_PCM then Такое впечатление, что FormatTag не читается. Вроде бы все стоит на своих местах и все правильно, но не работает... Ради экономии места код сокращаю. Код: Код:
type
EWavError = class(Exception);
TWaveFormat = packed record
wFormatTag: Word;
nChannels: Word;
nSamplesPerSec: DWORD;
nAvgBytesPerSec: DWORD;
nBlockAlign: Word;
wBitsPerSample: Word;
end;
TWavInfo = record
WaveFormat: TWaveFormat;
NumSamples: Integer;
MaxAmplitude: Integer;
Samples: packed array of array of Smallint;
end;
Const
WAVE_FORMAT_PCM = $0001;
type
TForm1 = class(TForm)
private
{ Private declarations }
FWavInfo: TWavInfo;
procedure UpdateScrollBar;
public
{ Public declarations }
end;
var
Form1: TForm1;
WavInfo: TWavInfo;
TxtFile : TextFile;
t:tstringlist;
i : integer;
Ini:Tinifile;
language:string;
implementation
{$R *.dfm}
{$R WindowsXP.res}
uses math, Unit2;
procedure RaiseWavError(const Msg: string);
begin
raise EWavError.Create(Msg);
end;
procedure ClearWavInfo(var WavInfo: TWavInfo);
begin
Finalize(WavInfo);
FillChar(WavInfo, SizeOf(WavInfo), 0);
end;
//Процедура чтения wav
procedure ReadWavInfo(const FileName: string; var WavInfo: TWavInfo);
type
TChunkName = packed array[0..3] of AnsiChar;
TRiffChunk = packed record
RiffSign: TChunkName;
RiffSize: Longword;
WaveSign: TChunkName;
end;
TChunk = packed record
Name: TChunkName;
Size: Longword;
end;
var
fs: TFileStream;
RiffChunk: TRiffChunk;
Chunk: TChunk;
FmtPos, DataPos, NewPos: Int64;
DataSize, NumSamples, BytsPerSample, I, J, Sample: Longword;
procedure DecRiffSize(Size: Longword);
begin
if RiffChunk.RiffSize < Size then RaiseWavError('Wav-файл повреждён');
Dec(RiffChunk.RiffSize, Size);
end;
begin
ClearWavInfo(WavInfo);
fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
try
fs.ReadBuffer(RiffChunk, SizeOf(RiffChunk));
if (RiffChunk.RiffSign <> 'RIFF') or (RiffChunk.WaveSign <> 'WAVE') then RaiseWavError('Это не wav-файл');
DecRiffSize(SizeOf(RiffChunk.WaveSign));
FmtPos := 0;
DataPos := 0;
Form1.Memo1.Lines.Add(RiffChunk.RiffSign);
Form1.Memo1.Lines.Add(RiffChunk.WaveSign);
while RiffChunk.RiffSize > 0 do
begin
fs.ReadBuffer(Chunk, SizeOf(Chunk));
DecRiffSize(Chunk.Size);
DecRiffSize(SizeOf(Chunk));
Form1.Memo1.Lines.Add(('Длина блока данных: ' + IntToStr(Chunk.Size)));
if Chunk.Name = 'fmt ' then
begin
if FmtPos <> 0 then RaiseWavError('Встретилось несколько секций "fmt"');
if Chunk.Size < SizeOf(WavInfo.WaveFormat) then RaiseWavError('Неверный размер секции "fmt"');
FmtPos := fs.Position;
end else
if Chunk.Name = 'data' then
begin
if DataPos <> 0 then RaiseWavError('Встретилось несколько секций "data"');
DataPos := fs.Position;
DataSize := Chunk.Size;
end;
Form1.Memo1.Lines.Add(Chunk.Name);
NewPos := fs.Position + Chunk.Size;
fs.Position := NewPos;
if fs.Position <> NewPos then RaiseWavError('Wav-файл повреждён');
end;
if FmtPos = 0 then RaiseWavError('Отсутствует секция "fmt"');
if DataPos = 0 then RaiseWavError('Отсутствует секция "data"');
fs.Position := FmtPos;
fs.ReadBuffer(WavInfo.WaveFormat, SizeOf(WavInfo.WaveFormat));
if WavInfo.WaveFormat.wFormatTag = WAVE_FORMAT_PCM then
begin
if WavInfo.WaveFormat.nChannels = 0 then RaiseWavError('Отсутствуют каналы');
case WavInfo.WaveFormat.wBitsPerSample of
8: BytsPerSample := 1;
16: BytsPerSample := 2;
else
RaiseWavError('Неверная разрядность сэмплов');
end;
BytsPerSample := WavInfo.WaveFormat.wBitsPerSample div 8;
if BytsPerSample = 0 then RaiseWavError('Неверная разрядность сэмплов');
NumSamples := DataSize div (BytsPerSample * WavInfo.WaveFormat.nChannels);
if NumSamples > LongWord(MaxInt) then RaiseWavError('Слишком много сэмплов');
SetLength(WavInfo.Samples, WavInfo.WaveFormat.nChannels, NumSamples);
fs.Position := DataPos;
Sample := 0;
for I := 1 to NumSamples do
begin
for J := 1 to WavInfo.WaveFormat.nChannels do
begin
fs.ReadBuffer(Sample, BytsPerSample);
case BytsPerSample of
1: Sample := Shortint(Sample);
2: Sample := SmallInt(Sample);
end;
WavInfo.Samples[J - 1, I - 1] := Sample;
if Abs(Sample) > WavInfo.MaxAmplitude then WavInfo.MaxAmplitude := Abs(Sample);
end;
end;
WavInfo.NumSamples := LongInt(NumSamples);
end;
Form1.Edit1.Text:=Form1.OpenDialog1.FileName;
Form1.Memo1.Lines.Add('Формат: $' + IntToHex(WavInfo.WaveFormat.wFormatTag, 4));
Form1.Memo1.Lines.Add('Каналов: ' + IntToStr(WavInfo.WaveFormat.nChannels));
Form1.Memo1.Lines.Add('Частота дискретизации: ' + IntToStr(WavInfo.WaveFormat.nSamplesPerSec) + ' сэмплов в секунду');
Form1.Memo1.Lines.Add('Скорость передачи данных: ' + IntToStr(WavInfo.WaveFormat.nAvgBytesPerSec) + ' байт в секунду');
Form1.Memo1.Lines.Add('Число байт для предоставления одного отчета: ' + IntToStr(WavInfo.WaveFormat.nBlockAlign));
Form1.Memo1.Lines.Add('Разрядность сэмплов: ' + IntToStr(WavInfo.WaveFormat.wBitsPerSample) + ' бит');
Form1.Memo3.Lines.Add('BytsPerSample: '+ IntToStr(BytsPerSample));
Form1.Memo3.Lines.Add('NumSamples: ' + IntToStr(WavInfo.NumSamples));
finally
fs.Free;
end;
end;
//Процедура открытия wav, построения графика
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
if OpenDialog1.Execute then
begin
MediaPlayer1.FileName:=OpenDialog1.FileName;
MediaPlayer1.Open;
MediaPlayer1.Play;
LengthBar.Max:=MediaPlayer1.Length;
LengthBar.Min:=MediaPlayer1.StartPos;
Timer1.Enabled:=True;
end;
begin
ClearWavInfo(FWavInfo);
tcDrawWav.Tabs.Clear;
pbDrawWav.Invalidate;
try
ReadWavInfo(OpenDialog1.FileName, FWavInfo);
except
ClearWavInfo(FWavInfo);
raise;
end;
sbTimePos.Position := sbTimePos.Min;
sbTimePos.PageSize := 0;
sbTimePos.Max := Max(FWavInfo.NumSamples + sbTimePos.Min - 1, sbTimePos.Min);
sbTimePos.PageSize := FWavInfo.NumSamples div tbTime.Position;
for i := 1 to FWavInfo.WaveFormat.nChannels do
begin
tcDrawWav.Tabs.Add('Channel №' + IntToStr(i));
end;
pbDrawWav.Invalidate;
end;
end;
//Процедура записи
procedure WriteWav(const FileName: string; const WavInfo: TWavInfo);
type
TChunkID = packed array[0..3] of Char;
THeader = packed record
ChunkID: TChunkID;
ChunkSize: Longword;
Format: TChunkID;
Subchunk1ID: TChunkID;
Subchunk1Size: Longword;
AudioFormat: Word;
NumChannels: Word;
SampleRate: Longword;
ByteRate: Longword;
BlockAlign: Word;
BitsPerSample: Word;
Subchunk2ID: TChunkID;
Subchunk2Size: Longword;
end;
var
Header: THeader;
NumSamples, BytsPerSample, I, J: Longword;
fs: TFileStream;
begin
NumSamples := WavInfo.NumSamples;
BytsPerSample := WavInfo.WaveFormat.wBitsPerSample div 8;
Header.ChunkID := 'RIFF';
Header.Format := 'WAVE';
Header.Subchunk1ID := 'fmt ';
Header.Subchunk1Size := 16;
Header.AudioFormat := WAVE_FORMAT_PCM;
Header.NumChannels := WavInfo.WaveFormat.nChannels;
Header.SampleRate := WavInfo.WaveFormat.nSamplesPerSec;
Header.BitsPerSample := BytsPerSample * 8;
Header.BlockAlign := Header.NumChannels * BytsPerSample;
Header.ByteRate := Header.SampleRate * Header.BlockAlign;
Header.Subchunk2ID := 'data';
Header.Subchunk2Size := NumSamples * Header.BlockAlign;
Header.ChunkSize := Header.Subchunk2Size + SizeOf(Header) - 8;
fs := TFileStream.Create(FileName, fmCreate);
try
fs.WriteBuffer(Header, SizeOf(Header));
for I := 1 to NumSamples do
begin
for J := 1 to Header.NumChannels do
begin
fs.WriteBuffer(WavInfo.Samples[J - 1, I - 1], BytsPerSample);
end;
end;
finally
fs.Free;
end;
end;
//Кнопка записи
procedure TForm1.Button4Click(Sender: TObject);
begin
if WavInfo.WaveFormat.wFormatTag = WAVE_FORMAT_PCM then
begin
if SaveDialog2.Execute then
begin
WriteWav(SaveDialog2.FileName, WavInfo);
end;
end;
end; |
|
#43
|
||||
|
||||
|
Цитата:
|
|
#44
|
|||
|
|||
|
Цитата:
|
|
#45
|
||||
|
||||
|
Цитата:
|