Generating unique ids for audio cds
In the cddb / freedb-project from this way of building unique ids can be found:
struct toc {
int min;
int sec;
int frame;
};
struct toc cdtoc[100];
int
read_cdtoc_from_drive(void)
{
/* Do whatever is appropriate to read the TOC of the CD
* into the cdtoc[] structure array.
*/
return (tot_trks);
}
int
cddb_sum(int n)
{
int ret;
/* For backward compatibility this algorithm must not change */
ret = 0;
while (n > 0) {
ret = ret + (n % 10);
n = n / 10;
}
return (ret);
}
unsigned long
cddb_discid(int tot_trks)
{
int i,
t = 0,
n = 0;
/* For backward compatibility this algorithm must not change */
i = 0;
while (i < tot_trks) {
n = n + cddb_sum((cdtoc[i].min * 60) + cdtoc[i].sec);
i++;
}
t = ((cdtoc[tot_trks].min * 60) + cdtoc[tot_trks].sec) -
((cdtoc[0].min * 60) + cdtoc[0].sec);
return ((n % 0xff) << 24 | t << 8 | tot_trks);
}
main()
{
int tot_trks;
tot_trks = read_cdtoc_from_drive();
printf("The discid is %08x", cddb_discid(tot_trks));
}
In the hightlighted part you see that the array cdtoc is referenced by cdtoc[tot_trks] although the count index started at zero. The program expects that cdtoc[tot_trks] has the data of the disc lead-out.
Here comes a Delphi sample which also shows how to calculate that lead-out. Please note that the demonstration using TMediaPlayer MediaPlayer1 does probably not work if the disc has more than audio data.
// get disc id like in the freedb database
function TForm1.get_discid : String;
const
FRAME_PER_SEC = 75;
type
tMSFRec = record
Minutes : byte; {least significant byte}
Seconds : byte;
Frames : byte;
NotUsed : byte; {most significant byte}
end;
// . . . . . . . . . . . . . .
function prg_sum(n:integer):Integer;
{
adds all digits of a number (in Germany, we say "Quersumme")
e.g. 1234 --> 1+2+3+4 --> 10
}
var
buf : string;
ib : Integer;
begin
buf := IntToStr(n);
Result := 0;
for ib := 1 to Length(buf) do Result := Result + (StrToInt(Copy(Buf,ib,1)));
end;
// . . . . . . . . . . . . . .
var
T,
N,
trackNumb : Integer;
tempTF : TMPTimeFormats;
leadOut : tMSFRec;
begin
With MediaPlayer1 do
begin
tempTF := TimeFormat;
TimeFormat := tfMSF;
// . . . . . . . . . . . . . .
// we'll have to caltulate the lead-out since it is not given
leadOut := tMSFRec(TrackPosition[tracks]); // first, take start of last track
with tMSFRec(TrackLength[tracks]) do
begin // next, add length of last track
leadOut.Minutes := leadOut.Minutes + Minutes;
leadOut.Seconds := leadOut.Seconds + Seconds;
leadOut.Frames := leadOut.Frames + Frames +1; // plus 1: next free frame
end;
with leadOut do // at least, correct overflows
begin
while Frames >= FRAME_PER_SEC do
begin
inc(Seconds);
dec(Frames,FRAME_PER_SEC);
end;
while Seconds >= 60 do
begin
inc(Minutes);
dec(Seconds,60);
end;
end;
// . . . . . . . . . . . . . .
N := 0;
T := 0;
for trackNumb := 1 to tracks do
begin
with tMSFRec(TrackPosition[trackNumb]) do begin
n := n + prg_sum((minutes * 60) + seconds);
if trackNumb = 1 then
begin
t := ((leadOut.minutes * 60) + leadOut.seconds) -
((minutes * 60) + seconds);
end;
end;
end;
result := IntToHex((((n mod $0ff) shl 24) Xor (t shl 8) Xor Tracks),8);
TimeFormat := tempTF;
end;
end;
back to Q&A