|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#31
|
||||
|
||||
Ночью заниматься этим лень, днём перепишу.
Je venus de nulle part 55.026263 с.ш., 73.397636 в.д. |
#32
|
|||
|
|||
Цитата:
|
#33
|
|||||
|
|||||
Цитата:
Цитата:
Цитата:
Цитата:
Для звука, обычно по оси OX (по абсциссе) откладывается время, а по оси OY (по ординате) откладывается амплитуда звука. Я сделал небольшой пример (смотри во вложении), он рисует волну так, как на рисунке angvelem сверху. А вот снизу слева на этом рисунке, это уже амплитудно-частотный график (эквалайзер), там уже скорее всего не обошлось без быстрого преобразования Фурье. Такого я никогда не делал, так что если тебе нужен именно такой график, то прийдётся подождать когда angvelem переведёт код с ассемблера на Delphi. Цитата:
|
Этот пользователь сказал Спасибо poli-smen за это полезное сообщение: | ||
Dmitry_DM (29.08.2012)
|
#34
|
|||
|
|||
Цитата:
|
#35
|
||||
|
||||
вот тут все рисуется есть исходник, там и класс, обеспечивающий БПФ
Понять, что хочет заказчик - бесценно, ведь он платит MasterCard |
#36
|
|||
|
|||
Я интегрировал пример от poli-smen в свою программу. Так сказать, удалось. Но так же, как и бар громкости (может кто помнит тему про муз. плеер), бар, который увеличивает масштаб гистограммы и волны, начинает работать при одном любом нажатии на него. Так же было и с баром громкости. Два раза совпасть не может. Это не в коде дело. Может это из-за трек бара от AlphaControl?
|
#37
|
||||
|
||||
Обновил вложение.
Je venus de nulle part 55.026263 с.ш., 73.397636 в.д. |
#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. Пример на Дельфи не вдохновил? Je venus de nulle part 55.026263 с.ш., 73.397636 в.д. Последний раз редактировалось 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
|
||||
|
||||
Цитата:
|