{
micsave.pas
This file is part of "Flocke's MP3 Info & Convert".
Version 1.0a - Always find the most current version at
http://flocke.vssd.de/prog/apps/pascal/mp3conv/
Copyright (C) 2005 Volker Siebert, Germany
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
}
unit micsave;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
const
WM_CHECKWINDOWPOS = WM_USER + 13;
type
TfrmConvert = class(TForm)
rbtWav: TRadioButton;
bvlWav: TBevel;
lblWavFile: TLabel;
edtWavFile: TEdit;
btnWavFile: TButton;
rbtRes: TRadioButton;
bvlRes: TBevel;
lblResFile: TLabel;
edtResFile: TEdit;
btnResFile: TButton;
lblResName: TLabel;
edtResName: TEdit;
lblResType: TLabel;
edtResType: TEdit;
btnOk: TButton;
btnCancel: TButton;
dlgSave: TSaveDialog;
procedure FormShow(Sender: TObject);
procedure btnResFileClick(Sender: TObject);
procedure btnWavFileClick(Sender: TObject);
procedure rbtResClick(Sender: TObject);
procedure rbtWavClick(Sender: TObject);
protected
procedure WMCheckWindowPos(var Msg: TMsg); message WM_CHECKWINDOWPOS;
private
{ Private-Deklarationen }
procedure ToggleControls;
public
{ Public-Deklarationen }
end;
var
frmConvert: TfrmConvert;
procedure ConvertThisFile(const Filename: string);
implementation
{$R *.dfm}
uses
MMSystem, MMReg, MP3Utils;
resourcestring
SNoValidMP3File = 'This file is no MP3 valid file!';
SFileAlreadyConverted = 'This file is already in converted format!';
SFileExistsOverwrite = ' already exists.'#13#10#13#10'Overwrite?';
SHasRiffHeaderTake = #13#10'has a RIFF WAVE header!'#13#10#13#10 +
'Take this header?';
SConversionSuccessful = 'Conversion successful!';
SWaveFilter = 'Wave audio (*.wav)|*.wav|All files|*.*';
SResourceFilter = 'Resource files (*.res)|*.res|All files|*.*';
//======================================================================
const
CResFileHeader: array [0 .. 7] of cardinal = (
$00000000, $00000020, $0000FFFF, $0000FFFF,
$00000000, $00000000, $00000000, $00000000
);
type
TResEntryHeader = packed record
dwResSize: LongInt; // Size of the pure resource data
dwHdrSize: LongInt; // Size of the header (incl. this)
end;
// Resource type as Z-terminated wide string
// Resource name as Z-terminated wide string
const
CResEntryTrailer: array [0 .. 3] of cardinal = (
$00000000, $00000030, $00000000, $00000000
);
procedure WriteResourceHeader(Stream: TStream; ResSize: LongInt;
const ResName, ResType: string);
var
reh: TResEntryHeader;
rn, rt: WideString;
begin
reh.dwResSize := ResSize;
reh.dwHdrSize := 24 + (Length(ResName) + 1 + Length(ResType) + 1) * 2;
rn := ResName;
rt := ResType;
Stream.WriteBuffer(CResFileHeader, 32);
Stream.WriteBuffer(reh, 8);
Stream.WriteBuffer(rt[1], 2 + 2 * Length(rt));
Stream.WriteBuffer(rn[1], 2 + 2 * Length(rn));
Stream.WriteBuffer(CResEntryTrailer, 16);
end;
//======================================================================
const
//FOURCC_RIFF = $46464952; { 'RIFF' }
FOURCC_WAVE = $45564157; { 'WAVE' }
FOURCC_fmt = $20746D66; { 'fmt ' }
FOURCC_fact = $74636166; { 'fact' }
FOURCC_data = $61746164; { 'data' }
type
TMp3RiffHeader = packed record
fccRiff: FOURCC;
dwFileSize: LongInt;
fccWave: FOURCC;
fccFmt: FOURCC;
dwFmtSize: LongInt;
mp3wfx: TMpegLayer3WaveFormat;
fccFact: FOURCC;
dwFactSize: LongInt;
lSizeInSamples: LongInt;
fccData: FOURCC;
dwDataSize: LongInt;
end;
procedure Mp3RiffHeaderFromInfo(var Riff: TMp3RiffHeader; const Header: TL3FHeader;
Length: LongInt);
const
CChannels: array [0 .. 3] of Word = (
2, 2, 2, 1
);
CFlags: array [boolean, 0 .. 1] of Cardinal = (
( MPEGLAYER3_FLAG_PADDING_OFF, MPEGLAYER3_FLAG_PADDING_ON ),
( MPEGLAYER3_FLAG_PADDING_ISO, MPEGLAYER3_FLAG_PADDING_ISO )
);
CSizeMismatch: array [boolean] of Integer = (
1, 2
);
begin
Riff.fccRiff := FOURCC_RIFF;
Riff.dwFileSize := Header.FileSize + SizeOf(TMp3RiffHeader);
Riff.fccWave := FOURCC_WAVE;
Riff.fccFmt := FOURCC_fmt;
Riff.dwFmtSize := SizeOf(TMpegLayer3WaveFormat);
Riff.mp3wfx.wfx.wFormatTag := WAVE_FORMAT_MPEGLAYER3;
Riff.mp3wfx.wfx.nChannels := CChannels[Header.Mode];
Riff.mp3wfx.wfx.nSamplesPerSec := l3f_header_freq_hz(Header);
Riff.mp3wfx.wfx.nAvgBytesPerSec := 125 * l3f_header_rate_kbps(Header);
Riff.mp3wfx.wfx.nBlockAlign := 1;
Riff.mp3wfx.wfx.wBitsPerSample := 0;
Riff.mp3wfx.wfx.cbSize := MPEGLAYER3_WFX_EXTRA_BYTES;
Riff.mp3wfx.wID := MPEGLAYER3_ID_MPEG;
Riff.mp3wfx.fdwFlags := CFlags[Header.XingHeader > 0, Header.Padding];
Riff.mp3wfx.nBlockSize := Header.LengthInBytes;
Riff.mp3wfx.nFramesPerBlock := 1;
Riff.mp3wfx.nCodecDelay := 1105; // 1 + (Standard MDTC Filterbank) + (1 Granule)
Riff.fccFact := FOURCC_fact;
Riff.dwFactSize := 4;
Riff.lSizeInSamples := (Header.TotalFrames - CSizeMismatch[Header.XingHeader > 0]) *
Header.LengthInSamples - Riff.mp3wfx.nCodecDelay;
Riff.fccData := FOURCC_data;
Riff.dwDataSize := Header.FileSize;
end;
//======================================================================
procedure ConvertThisFile(const Filename: string);
var
Header: TL3FHeader;
Length, Mp3Size: LongInt;
NewName: string;
Mp3Hdr, OldHdr: TMp3RiffHeader;
InStream, OutStream: TFileStream;
begin
Length := Layer3EstimateLength(Filename, Header);
if Length = 0 then
begin
MessageDlg(SNoValidMP3File, mtInformation, [mbOk], 0);
exit;
end;
frmConvert.edtWavFile.Text := ChangeFileExt(Filename, '.wav');
frmConvert.edtResName.Text := ChangeFileExt(ExtractFileName(Filename), '');
frmConvert.edtResFile.Text := ChangeFileExt(Filename, '.res');
if CompareText(FileName, frmConvert.edtWavFile.Text) = 0 then
frmConvert.rbtRes.Checked := true;
if frmConvert.ShowModal <> mrOk then
exit;
if frmConvert.rbtWav.Checked then
NewName := frmConvert.edtWavFile.Text
else
NewName := frmConvert.edtResFile.Text;
if CompareText(Filename, NewName) = 0 then
begin
MessageDlg(SFileAlreadyConverted, mtInformation, [mbOk], 0);
exit;
end;
if FileExists(NewName) then
if MessageDlg(NewName + SFileExistsOverwrite, mtConfirmation,
[mbOk, mbCancel], 0) <> mrOk then
begin
exit;
end;
Mp3RiffHeaderFromInfo(Mp3Hdr, Header, Length);
Mp3Size := SizeOf(Mp3Hdr);
InStream := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
try
if Header.FileOffset >= SizeOf(TMp3RiffHeader) - 12 then
begin
InStream.Position := 0;
InStream.ReadBuffer(OldHdr, 20);
if (OldHdr.fccRiff = FOURCC_RIFF) and
(OldHdr.dwFileSize <= Header.FileOffset + Header.FileSize) and
(OldHdr.fccWave = FOURCC_WAVE) and
(OldHdr.fccFmt = FOURCC_fmt) and
(OldHdr.dwFmtSize >= SizeOf(TMpegLayer3WaveFormat)) then
begin
case MessageDlg(Filename + SHasRiffHeaderTake,
mtConfirmation, [mbYes, mbNo, mbCancel], 0) of
mrYes: begin
Mp3Size := 0;
Header.FileOffset := 0;
Header.FileSize := OldHdr.dwFileSize;
end;
mrCancel: begin
InStream.Free;
exit;
end;
end;
end;
end;
OutStream := TFileStream.Create(NewName, fmCreate);
try
if frmConvert.rbtRes.Checked then
WriteResourceHeader(OutStream, Header.FileSize, frmConvert.edtResName.Text,
frmConvert.edtResType.Text);
if Mp3Size > 0 then
OutStream.WriteBuffer(Mp3Hdr, Mp3Size);
InStream.Position := Header.FileOffset;
OutStream.CopyFrom(InStream, Header.FileSize);
finally
OutStream.Free;
end;
finally
InStream.Free;
end;
MessageDlg(SConversionSuccessful, mtInformation, [mbOk], 0);
end;
//======================================================================
procedure TfrmConvert.ToggleControls;
begin
edtWavFile.Enabled := rbtWav.Checked;
btnWavFile.Enabled := rbtWav.Checked;
edtResName.Enabled := rbtRes.Checked;
edtResType.Enabled := rbtRes.Checked;
edtResFile.Enabled := rbtRes.Checked;
btnResFile.Enabled := rbtRes.Checked;
if rbtWav.Checked then
btnOk.Enabled := Trim(edtWavFile.Text) <> ''
else
btnOk.Enabled := Trim(edtResFile.Text) <> '';
end;
procedure TfrmConvert.rbtWavClick(Sender: TObject);
begin
rbtRes.Checked := not rbtWav.Checked;
ToggleControls;
end;
procedure TfrmConvert.rbtResClick(Sender: TObject);
begin
rbtWav.Checked := not rbtRes.Checked;
ToggleControls;
end;
procedure TfrmConvert.btnWavFileClick(Sender: TObject);
begin
dlgSave.Filter := SWaveFilter;
dlgSave.DefaultExt := 'wav';
dlgSave.InitialDir := ExtractFilePath(edtWavFile.Text);
dlgSave.FileName := edtWavFile.Text;
if dlgSave.Execute then
edtWavFile.Text := dlgSave.FileName;
end;
procedure TfrmConvert.btnResFileClick(Sender: TObject);
begin
dlgSave.Filter := SResourceFilter;
dlgSave.DefaultExt := 'res';
dlgSave.InitialDir := ExtractFilePath(edtWavFile.Text);
dlgSave.FileName := edtResFile.Text;
if dlgSave.Execute then
edtWavFile.Text := dlgSave.FileName;
end;
procedure TfrmConvert.FormShow(Sender: TObject);
begin
rbtWavClick(rbtWav);
PostMessage(Handle, WM_CHECKWINDOWPOS, 0, 0);
end;
procedure TfrmConvert.WMCheckWindowPos(var Msg: TMsg);
begin
if Left < Monitor.WorkAreaRect.Left + 10 then
Left := Monitor.WorkAreaRect.Left + 10
else if Left + Width > Monitor.WorkAreaRect.Right - 10 then
Left := Monitor.WorkAreaRect.Right - 10 - Width;
if Top < Monitor.WorkAreaRect.Top + 10 then
Top := Monitor.WorkAreaRect.Top + 10
else if Top + Height > Monitor.WorkAreaRect.Bottom - 10 then
Top := Monitor.WorkAreaRect.Bottom - 10 - Height;
end;
end.
|