TrackBar.SelEnd := Round(Finish*TrackBar.Max/AudioSize);
Marker1.Left := 8+Round(Start*(TrackBar.Max-20)/AudioSize);
Marker1.Visible := True;
Marker2.Left := 8+Round(Finish*(TrackBar.Max-20)/AudioSize);
Marker2.Visible := True;
PaintBox1.Repaint;
Exit;
end;
if (StartExists) and (FinishExists) then
begin
if AudioPosition<Start then
Start := AudioPosition
else
if AudioPosition>Finish then
Finish := AudioPosition;
TrackBar.SelStart := Round(Start*TrackBar.Max/AudioSize);
TrackBar.SelEnd := Round(Finish*TrackBar.Max/AudioSize);
Marker1.Left := 8+Round(Start*(TrackBar.Max-20)/AudioSize);
Marker1.Visible := True;
Marker2.Left := 8+Round(Finish*(TrackBar.Max-20)/AudioSize);
Marker2.Visible := True;
PaintBox1.Repaint;
Exit;
end;
end;
end;
procedure TMainForm.DeleteMarkers;
begin
Selection.StartExists := False;
Selection.FinishExists := False;
Marker1.Visible := False;
Marker2.Visible := False;
TrackBar.SelStart := 0;
TrackBar.SelEnd := 0;
PaintBox1.Repaint;
end;
procedure TMainForm.OpenButtonClick(Sender: TObject);
var
FileName, S, Ext: String;
i: Byte;
PCM: TPCMFile;
MP3: TMP3File;
EM1: TEM1File;
begin
if (Status<>'starting')and(Status<>'waiting') then Exit;
if OpenDialog.Execute then FileName := OpenDialog.FileName else Exit;
Status := 'opening';
AudioData.Data.Clear;
if GetFileAttributes(PChar(FileName)) and FILE_ATTRIBUTE_READONLY = FILE_ATTRIBUTE_READONLY then
SetFileAttributes(PChar(FileName), GetFileAttributes(PChar(FileName)) xor FILE_ATTRIBUTE_READONLY);
Ext := ExtractFileExt(FileName);
for i := 1 to Length(Ext) do Ext[i] := UpCase(Ext[i]);
if Ext = '.WAV' then
begin
PCM := TPCMFile.Open(FileName);
PCM.ReadAudioData(AudioData);
PCM.Destroy;
end;
if Ext = '.MP3' then
begin
MP3 := TMP3File.Open(FileName);
MP3.ReadAudioData(AudioData);
MP3.Destroy;
end;
if Ext = '.EM1' then
begin
EM1 := TEM1File.Open(FileName);
EM1.ReadAudioData(AudioData);
EM1.Destroy;
end;
Str(AudioData.nChannels, S);
AudioOptionsForm.nChannelsText.Caption := S + ' channels';
Str(AudioData.nBitsPerSample, S);
AudioOptionsForm.nBitsPerSampleText.Caption := S + ' bits';
Str(AudioData.nSamplesPerSec, S);
AudioOptionsForm.nSamplesPerSecText.Caption := S + ' Hz';
AudioPosition := 0;
AudioData.Calculate_nBlockAlign;
SetAudioPosition;
DeleteMarkers;
Status := 'waiting';
end;
procedure TMainForm.PlayButtonClick(Sender: TObject);
begin
if Status<>'waiting' then Exit;
if OutDeviceComboBox.ItemIndex = -1 then Exit;
if AudioPosition*AudioData.nBlockAlign >= AudioData.Data.Size then Exit;
Status := 'playing';
PlayThread := TPlayThread.Create(False);
end;
procedure TPlayThread.Execute;
const
BlockSize = 1024*24;
var
hEvent: THandle;
WaveFormatEx: TWaveFormatEx;
WaveHdr: array [0..1] of TWaveHdr;
Buf: array [0..1] of array [0..BlockSize-1] of Byte;
i: Cardinal;
begin
with WaveFormatEx do
begin
wFormatTag := WAVE_FORMAT_PCM;
nChannels := AudioData.nChannels;
nSamplesPerSec := AudioData.nSamplesPerSec;
wBitsPerSample := AudioData.nBitsPerSample;
nBlockAlign := wBitsPerSample div 8 * nChannels;
nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
cbSize := 0;
end;
hEvent := CreateEvent(nil, False, False, nil);
if WaveOutOpen(@WaveOut, MainForm.OutDeviceComboBox.ItemIndex , @WaveFormatEx, hEvent, 0, CALLBACK_EVENT) <> MMSYSERR_NOERROR then
begin
Status := 'waiting';
CloseHandle(hEvent);
Terminate;
Exit;
end;
MainForm.PlayButton.Flat := True;
for i := 0 to 1 do
begin
WaveHdr[i].lpData := @Buf[i];
WaveHdr[i].dwBufferLength := BlockSize;
AudioData.Data.Position := AudioPosition*AudioData.nBlockAlign;
if i<>1 then
begin
AudioData.Data.Read(Buf[i], BlockSize);
AudioPosition := AudioPosition + BlockSize div AudioData.nBlockAlign;
if AudioPosition*AudioData.nBlockAlign >= AudioData.Data.Size then AudioPosition := AudioData.Data.Size div AudioData.nBlockAlign;
end;
WaveOutPrepareHeader(WaveOut, @WaveHdr[i], SizeOf(TWaveHdr));
end;
i := 0;
while (not Terminated) and (AudioData.Data.Position<AudioData.Data.Size) do
begin
WaveOutWrite(WaveOut, @WaveHdr[i], SizeOf(TWaveHdr));
WaitForSingleObject(hEvent, INFINITE);
i := i xor 1;
AudioData.Data.Position := AudioPosition*AudioData.nBlockAlign;
AudioData.Data.Read(Buf[i], BlockSize);
AudioPosition := AudioPosition + (BlockSize div AudioData.nBlockAlign);
if AudioPosition*AudioData.nBlockAlign >= AudioData.Data.Size then AudioPosition := AudioData.Data.Size div AudioData.nBlockAlign;
MainForm.SetAudioPosition;
end;
WaveOutReset(WaveOut);
for i := 0 to 1 do WaveOutUnprepareHeader(WaveOut, @WaveHdr[i], SizeOf(WaveHdr));
WaveOutClose(WaveOut);
CloseHandle(hEvent);
if not Terminated then Terminate;
MainForm.PlayButton.Flat := False;
Status := 'waiting';
end;
procedure TMainForm.RecordButtonClick(Sender: TObject);
begin
if (Status<>'waiting')and(Status<>'starting') then Exit;
if InDeviceComboBox.ItemIndex = -1 then Exit;
Status := 'recording';
RecordThread := TRecordThread.Create(False);
end;
procedure TRecordThread.Execute;
const
BlockSize = 1024*24;
BufNumber = 8;
var
hEvent: THandle;
WaveFormatEx: TWaveFormatEx;
WaveHdr: array [0..BufNumber-1] of TWaveHdr;
Buf: array [0..BufNumber-1] of array [0..BlockSize-1] of Byte;
i: Cardinal;
begin
with WaveFormatEx do
begin
wFormatTag := WAVE_FORMAT_PCM;
nChannels := AudioData.nChannels;
nSamplesPerSec := AudioData.nSamplesPerSec;
wBitsPerSample := AudioData.nBitsPerSample;
nBlockAlign := wBitsPerSample div 8 * nChannels;
nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
cbSize := 0;
end;
hEvent := CreateEvent(nil, False, False, nil);
if WaveInOpen(@WaveIn, MainForm.InDeviceComboBox.ItemIndex , @WaveFormatEx, hEvent, 0, CALLBACK_EVENT) <> MMSYSERR_NOERROR then
begin
Status := 'waiting';
CloseHandle(hEvent);
Terminate;
Exit;
end;
MainForm.RecordButton.Flat := True;
for i := 0 to BufNumber-1 do
begin
WaveHdr[i].lpData := @Buf[i];
WaveHdr[i].dwBufferLength := BlockSize;
WaveInPrepareHeader(WaveIn, @WaveHdr[i], SizeOf(TWaveHdr));
end;
WaveInStart(WaveIn);
WaitForSingleObject(hEvent, INFINITE);
for i := 0 to BufNumber-1 do
WaveInAddBuffer(WaveIn, @WaveHdr[i], SizeOf(TWaveHdr));
i := BufNumber-1;
while not Terminated do
begin
if i = BufNumber-1 then i := 0 else Inc(i);
if (WaveHdr[i].dwFlags and WHDR_DONE) <> WHDR_DONE then
WaitForSingleObject(hEvent, INFINITE);
AudioData.Data.Position := AudioPosition*AudioData.nBlockAlign;
AudioData.Data.Write(Buf[i], WaveHdr[i].dwBytesRecorded);
AudioPosition := AudioPosition + (WaveHdr[i].dwBytesRecorded div AudioData.nBlockAlign);
WaveInAddBuffer(WaveIn, @WaveHdr[i], SizeOf(TWaveHdr));
MainForm.SetAudioPosition;
end;
WaveInReset(WaveIn);
for i := 0 to BufNumber-1 do
WaveInUnprepareHeader(WaveIn, @WaveHdr[i], SizeOf(WaveHdr));
WaveInClose(WaveIn);
CloseHandle(hEvent);
if not Terminated then Terminate;
with MainForm.PositionSpinEdit do
begin
Value := AudioPosition;
MinValue := 0;
MaxValue := AudioData.Data.Size div AudioData.nBlockAlign;;
end;
MainForm.RecordButton.Flat := False;
Status := 'waiting';
end;
procedure TMainForm.PauseButtonClick(Sender: TObject);
begin
if Status = 'playing' then PlayThread.Terminate;
if Status = 'recording' then RecordThread.Terminate;
end;
procedure TMainForm.TrackBarChange(Sender: TObject);
var
AudioSize: Cardinal;
begin
if Status<>'waiting' then Exit;
with AudioData do
AudioSize := Data.Size div nBlockAlign;
if TrackBar.Position <> Round(AudioPosition*TrackBar.Max/AudioSize) then
begin
AudioPosition := Round(TrackBar.Position/TrackBar.Max*AudioSize);
SetAudioPosition;
end;
end;
procedure TMainForm.PositionSpinEditChange(Sender: TObject);
begin
if Status<>'waiting' then Exit;
AudioPosition := PositionSpinEdit.Value;
SetAudioPosition;
end;
procedure TMainForm.SaveButtonClick(Sender: TObject);
var
FileName, Ext, EncMode, StereoMode, BitRate: String;
i: Byte;
Code: Integer;
PCM: TPCMFile;
MP3: TMP3File;
EM1: TEM1File;
begin
if Status<>'waiting' then Exit;
if SaveDialog.Execute then
FileName := SaveDialog.FileName else Exit;
Ext := ExtractFileExt(FileName);
for i := 1 to Length(Ext) do Ext[i] := UpCase(Ext[i]);
if Ext = '.WAV' then
begin
PCM := TPCMFile.Create(FileName, AudioData);
PCM.Destroy;
end;
if Ext = '.MP3' then
begin
if RadioButton1.Checked then
begin
BitRate := MP3OptionsForm.ConstantBitRateComboBox.Text;
EncMode := '-b';
end;
if RadioButton2.Checked then
begin
BitRate := MP3OptionsForm.AverageBitRateComboBox.Text;
EncMode := '--abr';
end;
if RadioButton3.Checked then
begin
Str(MP3OptionsForm.VariableBitrateComboBox.ItemIndex, BitRate);
EncMode := '-V';
end;
case MP3OptionsForm.StereoModeComboBox.ItemIndex of
0: StereoMode := 's';
1: StereoMode := 'j';
2: StereoMode := 'f';
3: StereoMode := 'd';
4: StereoMode := 'm';
end;
MP3 := TMP3File.Create(FileName, AudioData, BitRate, EncMode, StereoMode);
MP3.Destroy;
end;
if Ext = '.EM1' then
begin
EM1 := TEM1File.Create(FileName, AudioData);
EM1.Destroy;
end;
end;
procedure TMainForm.SetMarkerButtonClick(Sender: TObject);
begin
SetMarker;
end;
procedure TMainForm.DeleteMarkersButtonClick(Sender: TObject);
begin
DeleteMarkers;
end;
procedure TMainForm.CopyButtonClick(Sender: TObject);
var
AudioSize: Cardinal;
S: String;
begin
if Status<>'waiting' then Exit;
Status := 'editing';
with AudioData do
AudioSize := Data.Size div nBlockAlign;
with Selection do
begin
if not StartExists or not FinishExists then
begin
DeleteMarkers;
Start := 0;
Finish := AudioSize-1;
end;
CopyAudio(AudioData, AudioClipBoard, Start, Finish);
end;
Str(AudioClipBoard.Data.Size div AudioClipBoard.nBlockAlign div AudioClipBoard.nSamplesPerSec, S);
Memo1.Text := 'В буффере ' + S + ' сек.';
Status := 'waiting';
end;
procedure TMainForm.DeleteButtonClick(Sender: TObject);
var
AudioSize: Cardinal;
begin
if Status<>'waiting' then Exit;
Status := 'editing';
SaveUndoInfo;
with AudioData do
AudioSize := Data.Size div nBlockAlign;
with Selection do
begin
if not StartExists or not FinishExists then
begin
DeleteMarkers;
Start := 0;
Finish := AudioSize-1;
end;
DeleteAudio(AudioData, Start, Finish);
DeleteMarkers;
AudioPosition := Start;
SetAudioPosition;
end;
Status := 'waiting';
end;
procedure TMainForm.CutButtonClick(Sender: TObject);
var
AudioSize: Cardinal;
S: String;
begin
if Status<>'waiting' then Exit;
Status := 'editing';
SaveUndoInfo;
with AudioData do
AudioSize := Data.Size div nBlockAlign;
with Selection do
begin
if not StartExists or not FinishExists then
begin
DeleteMarkers;
Start := 0;
Finish := AudioSize-1;
end;
CopyAudio(AudioData, AudioClipBoard, Start, Finish);
DeleteAudio(AudioData, Start, Finish);
DeleteMarkers;
AudioPosition := Start;
SetAudioPosition;
end;
Str(AudioClipBoard.Data.Size div AudioClipBoard.nBlockAlign div AudioClipBoard.nSamplesPerSec, S);
Memo1.Text := 'В буффере ' + S + ' сек.';
Status := 'waiting';
end;
procedure TMainForm.ClearButtonClick(Sender: TObject);
var
AudioSize, i: Cardinal;
Buf: Byte;
begin
if Status<>'waiting' then Exit;
Status := 'editing';
SaveUndoInfo;
with AudioData do
AudioSize := Data.Size div nBlockAlign;
with Selection do
begin
if not StartExists or not FinishExists then
begin
DeleteMarkers;
Start := 0;
Finish := AudioSize-1;
end;
Buf := 0;
AudioData.Data.Position := Start*AudioData.nBlockAlign;
for i := Start*AudioData.nBlockAlign to Finish*AudioData.nBlockAlign-1 do
AudioData.Data.Write(Buf, 1);
end;
Status := 'waiting';
PaintAudioGraph;
end;
procedure TMainForm.PasteButtonClick(Sender: TObject);
var
MP3: TMP3File;
PCM: TPCMFile;
EM1: TEM1File;
i: Byte;
FileName, S, Ext: String;
TempAudio: TAudioData;
begin
if (Status<>'waiting')and(Status<>'starting') then Exit;
if Sender = PasteFileButton then
begin
if OpenDialog.Execute then FileName := OpenDialog.FileName else Exit;
Status := 'opening';
Ext := ExtractFileExt(FileName);
if GetFileAttributes(PChar(FileName)) and FILE_ATTRIBUTE_READONLY = FILE_ATTRIBUTE_READONLY then
SetFileAttributes(PChar(FileName), GetFileAttributes(PChar(FileName)) xor FILE_ATTRIBUTE_READONLY);
TempAudio := TAudioData.Create;
for i := 1 to Length(Ext) do Ext[i] := UpCase(Ext[i]);
if Ext = '.WAV' then
begin
PCM := TPCMFile.Open(FileName);
PCM.ReadAudioData(TempAudio);
PCM.Destroy;
end;
if Ext = '.MP3' then
begin
MP3 := TMP3File.Open(FileName);
MP3.ReadAudioData(TempAudio);
MP3.Destroy;
end;
if Ext = '.EM1' then
begin
EM1 := TEM1File.Open(FileName);
EM1.ReadAudioData(TempAudio);
EM1.Destroy;
end;
SetnSamplesPerSec(TempAudio, AudioData.nSamplesPerSec);
SetnBitsPerSample(TempAudio, AudioData.nBitsPerSample);
SetnChannels(TempAudio, AudioData.nChannels);
end
else
begin
SetnSamplesPerSec(AudioClipBoard, AudioData.nSamplesPerSec);
SetnBitsPerSample(AudioClipBoard, AudioData.nBitsPerSample);
SetnChannels(AudioClipBoard, AudioData.nChannels);
end;
Status := 'editing';
SaveUndoInfo;
if Sender <> PasteFileButton then
Case PasteModeComboBox.ItemIndex of
0: InsertAudio(AudioClipBoard, AudioData, AudioPosition);
1: OverWriteAudio(AudioClipBoard, AudioData, AudioPosition);
2: MixAudio(AudioClipBoard, AudioData, AudioPosition);
end
else
Case PasteModeComboBox.ItemIndex of
0: InsertAudio(TempAudio, AudioData, AudioPosition);
1: OverWriteAudio(TempAudio, AudioData, AudioPosition);
2: MixAudio(TempAudio, AudioData, AudioPosition);
end;
DeleteMarkers;
SetAudioPosition;
SetMarker;
if Sender <> PasteFileButton then
AudioPosition := AudioPosition + AudioClipBoard.Data.Size div AudioData.nBlockAlign - 1
else
begin
AudioPosition := AudioPosition + TempAudio.Data.Size div AudioData.nBlockAlign - 1;
TempAudio.Destroy;
end;
SetAudioPosition;
SetMarker;
Status := 'waiting';
end;
procedure TMainForm.PasteSilenceButtonClick(Sender: TObject);
var
i: Cardinal;
b: Byte;
TempAudio: TAudioData;
begin