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