{
----------------------------------------------------------
MAS-CompMaker was used to generate this code
MAS-CompMaker, 2000-2001?Mats Asplund
----------------------------------------------------------
Component Name: Tmp3Tag
Author: Slightly improved and redone from a class made by
Andrey V. Sorokin, into a component by Mats Asplund.
Creation: 2001-11-08
Version: 1.0
Description: A component for reading and writing mp3-tags.
Credit: Andrey V.Sorokin
Saint-Petersburg, Russia
anso@mail.ru
anso@usa.net
http://anso.da.ru
http://anso.virtualave.net
E-mail: masprod@telia.com
Site: http://go.to/masdp
Legal issues: Copyright(c) 1999,2000 by Andrey V.Sorokin.
All rights reserved 2001?by Mats Asplund.
Usage:
This software is provided 'as-is', without any express or
implied warranty. In no event will the author be held liable
for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it
and redistribute it freely, subject to the following
restrictions:
1. The origin of this software must not be misrepresented,
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the productdo
cumentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
4. If you decide to use this software in any of your applications.
Send me an EMail and tell me about it.
Quick Reference:
Tmp3Tag inherits from TComponent.
Key-Properties:
TagPresent: True if loaded tag seems to be OK.
TagModified: True if anything changed.
v1Tag: True if ID3v1, false if ID3v1.1
Title: Music title
Artist: Performer
Year: Year as 4-chars string.
Album: Album title
Track: Track number (only if not v1)
Comment: Comment
GenreID: Genre ID (see fID3Genres which contains genres list as
TStrings)
Genre: Genre as string
Key-Methods:
LoadTag: Load tag from ABuf (max ABufSz)
LoadTagFromStream: Find ID3tag in AStream (max AStreamSz bytes from current
position) and Load it. If success then
returns offset to
tag, else
-1.
LoadTagFromFile: Load ID3Tag from file AFileName
SaveTag: Write tag into ABuf (max ABufSz bytes), clear Modified.
SaveTagToStream: Write tag ito current position of AStream, clear Modified.
SaveTagToFile: Add/Update tag in file AFileName, clear Modified.
DeleteTagFromFile: Delete tag from file AFileName (if it exists).
--------------------------------------------------------------------------------
}
unit mp3Tag;
{ Max. number of supported comment fields }
WMA_FIELD_COUNT = 7;
{ Names of supported comment fields }
WMA_FIELD_NAME: array [1..WMA_FIELD_COUNT] of WideString =
('WM/TITLE', 'WM/AUTHOR', 'WM/ALBUMTITLE', 'WM/TRACK', 'WM/YEAR',
'WM/GENRE', 'WM/DESCRIPTION');
{ Max. number of characters in tag field }
WMA_MAX_STRING_SIZE = 250;
type
{ Object ID }
ObjectID = array [1..16] of Char;
{ Tag data }
TagData = array [1..WMA_FIELD_COUNT] of WideString;
{ File data - for internal use }
FileData = record
FileSize: Integer;
{ File size (bytes) }
MaxBitRate: Integer;
{ Max. bit rate (bps) }
Channels: Word;
{ Number of channels }
SampleRate: Integer;
{ Sample rate (hz) }
ByteRate: Integer;
{ Byte rate }
Tag: TagData;
{ WMA tag information }
end;
{ ********************* Auxiliary functions &
procedures ******************** }
function ReadFieldString(const Source: TStream;
DataSize: Word): WideString;
var
Iterator, StringSize: Integer;
FieldData: array [1..WMA_MAX_STRING_SIZE * 2] of Byte;
begin
{ Read field data and convert to unicode string }
Result := '';
StringSize := DataSize div 2;
if StringSize > WMA_MAX_STRING_SIZE then
StringSize := WMA_MAX_STRING_SIZE;
Source.ReadBuffer(FieldData, StringSize * 2);
Source.Seek(DataSize - StringSize * 2, soFromCurrent);
for Iterator := 1 to StringSizedo
Result := Result +
WideChar(FieldData[Iterator * 2 - 1] + (FieldData[Iterator * 2] shl 8));
end;
procedure ReadTagStandard(const Source: TStream;
var Tag: TagData);
var
Iterator: Integer;
FieldSize: array [1..5] of Word;
FieldValue: WideString;
begin
{ Read standard tag data }
Source.ReadBuffer(FieldSize, SizeOf(FieldSize));
for Iterator := 1 to 5do
if FieldSize[Iterator] > 0 then
begin
{ Read field value }
FieldValue := ReadFieldString(Source, FieldSize[Iterator]);
{ Set corresponding tag field if supported }
case Iterator of
1: Tag[1] := FieldValue;
2: Tag[2] := FieldValue;
4: Tag[7] := FieldValue;
end;
procedure ReadTagExtended(const Source: TStream;
var Tag: TagData);
var
Iterator1, Iterator2, FieldCount, DataSize, DataType: Word;
FieldName, FieldValue: WideString;
begin
{ Read extended tag data }
Source.ReadBuffer(FieldCount, SizeOf(FieldCount));
for Iterator1 := 1 to FieldCountdo
begin
{ Read field name }
Source.ReadBuffer(DataSize, SizeOf(DataSize));
FieldName := ReadFieldString(Source, DataSize);
{ Read value data type }
Source.ReadBuffer(DataType, SizeOf(DataType));
{ Read field value only if string }
if DataType = 0 then
begin
Source.ReadBuffer(DataSize, SizeOf(DataSize));
FieldValue := ReadFieldString(Source, DataSize);
end
else
Source.Seek(DataSize, soFromCurrent);
{ Set corresponding tag field if supported }
for Iterator2 := 1 to WMA_FIELD_COUNTdo
if UpperCase(Trim(FieldName)) = WMA_FIELD_NAME[Iterator2] then
function ReadData(const FileName: string;
var Data: FileData): Boolean;
var
Source: TFileStream;
ID: ObjectID;
Iterator, ObjectCount, ObjectSize, Position: Integer;
begin
{ Read file data }
try
Source := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
Data.FileSize := Source.Size;
{ Check for existing header }
Source.ReadBuffer(ID, SizeOf(ID));
if ID = WMA_HEADER_ID then
begin
Source.Seek(8, soFromCurrent);
Source.ReadBuffer(ObjectCount, SizeOf(ObjectCount));
Source.Seek(2, soFromCurrent);
{ Read all objects in header and get needed data }
for Iterator := 1 to ObjectCountdo
function IsValid(const Data: FileData): Boolean;
begin
{ Check for data validity }
Result :=
(Data.MaxBitRate > 0) and (Data.MaxBitRate < 320000) and
((Data.Channels = WMA_CM_MONO) or (Data.Channels = WMA_CM_STEREO)) and
(Data.SampleRate >= 8000) and (Data.SampleRate <= 96000) and
(Data.ByteRate > 0) and (Data.ByteRate < 40000);
end;
function TWMAfile.ReadFromFile(const FileName: string): Boolean;
var
Data: FileData;
begin
{ Reset variables and load file data }
FResetData;
FillChar(Data, SizeOf(Data), 0);
Result := ReadData(FileName, Data);
{ Process data if loaded and valid }
if Result and IsValid(Data) then