Projekte > Optische Laufwerke > Medieninformationen

CD Text (MMC)

READ TOC/PMA/ATIP Command - Operation Code $43

Response Format 0101b: CD-TEXT

CD Text ist in der Regel auf AudioCDs zu finden. Jedoch kann nicht jedes Laufwerk diesen auch lesen. Er wird mit Read TOC/PMA/ATIP Command in Verbindung mit dem Antwortformat CD-Text abgerufen.

Das READ TOC/PMA/ATIP Command wird in der MMC-6 in den Kapitel 6.25 ff beschrieben. Der READ TOC/PMA/ATIP Command Descriptor Block ist in Kapitel 6.25.2.1 dargestellt:

  7 6 5 4 3 2 1 0
0 Operation Code = $43
1 Reserviert MSF = 1b Reserviert
2 Reserviert Format = 0101b
3 Reserviert
4
5
6 Track/Session Number ($00)
7 Allocation Length
8
9 Control

 

Zu setzende Werte:

Operation Code: $43 - READ TOC/PMA/ATIP Command.

MSF: 1b - Die Adressen sollen in MSF angegeben werden (0b = LBA). Das Bit muss hier nicht gesetzt werden, da der ATIP als MSF Adresse definiert ist.

Format: 0100b - ATIP.

Track/Session Number: $00 - Ist hier reserviert.

Allocation Length: $0020 - Länge der Antwortstruktur. Das Response Format 0100b für ATIP ist bis zu 32 Byte lang.

Control - ?

Antwortstruktur

Eine knappe Beschreibung gibt es in der MMC-6 Kapitel 2.25.3.7. Etwas ausführlicher ist die Anlage J zu MMC-3.

  7 6 5 4 3 2 1 0
0 CD-TEXT Data Length
1
2 Beim CD-Text Format reserviert.
3
  CD-Text Descriptoren
0..17 CD-Text Pack Data

 

CD-Text Data Length - Gibt in Bytes an, wie lang die folgende Datenstruktur ist.

Das CD-Text Pack Data Format:

Byte CD-Text Pack Data Format
0 Header Feld ID1: Packtypindikator
1 Header Feld ID2: Tracknummer
2 Header Feld ID3: Packnummer
3 Header Feld ID4: Blocknummer und Zeichenpositionindicator
4
..
15
Text Datenfelder Byte 0..11
16 CRC Feld Byte 0 oder reserviert.
17 CRC Feld Byte 1 oder reserviert.

 

Das erste Headerbyte gibt den Typ der Daten an. Das zweite den Track, zu welchem das erste Datenbyte gehört. Das dritte Byte ist der Zähler für das Pack und das vierte beinhaltet drei Werte (Siehe unten). Die Definitionen für die Packtypen sind:

Wert Beschreibung Inhalt
$80 Liste mit dem Titel des Albums (ID2 = $00) und
den Titeln der Tracks (ID2 = %01...$63).
ASCII
$81 Liste mit den Namen der Interpreten. ASCII
$82 Name des Texter (Songwriter) ASCII
$83 Name des Komponisten (Composer) ASCII
$84 Name des Arrangeurs (Arranger) ASCII
$85 Nachricht vom Inhalteanbieter und/oder Künstler ASCII
$86 Discidentifikationinformation Binär
$87 Genreidentifkation und Genreinformation Binär
$88 Table of Content Information Binär
$89 Zweite Table of Content Information Binär
$8A Reserviert ---
$8B Reserviert ---
$8C Reserviert ---
$8D Nur für den Inhalteanbieter reserviert. ?
$8E Liste mit UPC/EAN Code des Albums und eventuell den ISRC Codes aller Tracks. ASCII
$8F Größeninformation über den Block. Binär

 

Das vierte Headerbyte:

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
DBCC Blocknummer Zeichenposition

 

DBCC ist die Double Byte Character Code indication und gibt an, ob die Zeichen in den Daten aus einem oder zwei Byte bestehen. Die Blocknummer gibt an, welcher Block gerade angezeigt wird. Dies können bis zu acht gleichzeitig sein. In der Regel werden Blöcke für die Bereitstellung der Informationen in verschiedenen Sprachen verwendet. Der Zeichenpositionindicator gibt an, wieviele Datenbytes bereits in vorhergehenden Block enthalten waren. Auf Grund der Begrenzung auf vier Bit werden maximal 15 angegeben auch wenn es mehr sein sollten (Siehe Beispiel unten). Die Zeichenketten werden mit dem Zeichen #0 abgeschlossen.

Beispiel für einen CD-Text Block.

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
$80 $00 $00 $00 M i a .       W i l l k $DE 23
$80 $00 $01 $0C o m m e n   i m   C l u $EA 0F
$80 $00 $02 $0F b #0 K a p i t ä n #0 M e $8A 7A
$80 $02 $03 $02 i n   F r e u n d #0 M a $26 C4
$80 $03 $04 $02 u s e n #0 D u #0 1 0 0   $8C 3C
$80 $05 $05 $04 P r o z e n t #0 M a g i $7A A7
$80 $06 $06 $04 s c h #0 D e i n e t w e $87 15
$80 $07 $07 $08 g e n #0 V e r f o l g e $0C B3
$80 $08 $08 $08 r #0 G l ü c k s s t e r $BE 52
$80 $09 $09 $0A n #0 H a l t   S t i l l $9E D3
$80 $0A $0A $0A #0 D i e   A u s s i c h $71 ED
$80 $0B $0B $0B t #0 #0 #0 #0 #0 #0 #0 #0 #0 #0 #0 $18 BD
$81 $00 $0C $00 M i a . #0 #0 #0 #0 #0 #0 #0 #0 $E5 9C
$81 $08 $0D $00 #0 #0 #0 #0 #0 #0 #0 #0 #0 #0 #0 #0 $15 40
$86 $00 $0E $00 38 38 36 39 37 33 32 31 32 33 32 00 $C1 69
$8F $00 $0F $00 00 01 0B 03 0C 02 00 00 00 00 01 00 $59 15
$8F $01 $10 $00 00 00 00 00 00 00 00 03 11 00 00 00 $65 5E
$8F $02 $11 $00 00 00 00 00 00 00 00 00 00 00 00 00 $7E DB

 

Weitere Erläuterungen hierzu wird es im Kapitel Audio-CD (CDDA) geben.

 

Deklarationen

 
  {
  *  Für die Auswertung.
  }
  const
    RespFmtTOC    = $00;
    RespFmtMSI    = $01;
    RespFmtRawTOC = $02;
    RespFmtPMA    = $03;
    RespFmtATIP   = $04;
    RespFmtCDTEXT = $05;
 
  type
    TCDTextPack = Array[0..17] of Byte;

    TTableOfContentsCDText = record
      DataLength : Integer;
      PackCount  : Integer;
      Pack       : Array of TCDTextPack;
    end;
 
  {
  *  Für den Befehl.
  }
  const
    SCSIOP_READ_TOC = $43;
 
  const
    CDTEXT_PACK_ALBUM_NAME = $80;
    CDTEXT_PACK_PERFORMER  = $81;
    CDTEXT_PACK_SONGWRITER = $82;
    CDTEXT_PACK_COMPOSER   = $83;
    CDTEXT_PACK_ARRANGER   = $84;
    CDTEXT_PACK_MESSAGES   = $85;
    CDTEXT_PACK_DISC_ID    = $86;
    CDTEXT_PACK_GENRE      = $87;
    CDTEXT_PACK_TOC_INFO   = $88;
    CDTEXT_PACK_TOC_INFO2  = $89;
    CDTEXT_PACK_UPC_EAN    = $8E;
    CDTEXT_PACK_SIZE_INFO  = $8F;
 
  type
    TREAD_TOC_PMA_ATIP_CDTEXT_DATA_HEADER = record
      DataLength : Word;
      Reserved1  : Byte;
      Reserved2  : Byte;
    >end;

  type
    TREAD_TOC_PMA_ATIP_CDTEXT_DATA_BLOCK = record
      Header : Array[0..3] of Byte;
      Data   : Array[0..11] of AnsiChar;
      CRC    : Array[0..1] of Byte;
    end;
    PREAD_TOC_PMA_ATIP_CDTEXT_DATA_BLOCK = ^TREAD_TOC_PMA_ATIP_CDTEXT_DATA_BLOCK;

  type
    TREAD_TOC_PMA_ATIP_CDTEXT_DATA = record
      Header : TREAD_TOC_PMA_ATIP_CDTEXT_DATA_HEADER;
      Blocks : Array[$00..$63] of TREAD_TOC_PMA_ATIP_CDTEXT_DATA_BLOCK;
    end;
    PREAD_TOC_PMA_ATIP_CDTEXT_DATA = ^TREAD_TOC_PMA_ATIP_CDTEXT_DATA;
          

 

Ausführung und Auswertung

Nach dem Ausfüllen des Command Descriptors Blockes wird die Abfrage ausgeführt. Eine Auswertung erfolgt derzeit jedoch nicht weiter.

 
  function TOptDrives.ReadTOCPMAATIP_CDText(aDevice: THandle): Boolean;
  {*******************************************************************************
  *  Den rohen CD-Text ermitteln.
  }
  var
    READ_TOC_PMA_ATIP_CDB  : TREAD_TOC_PMA_ATIP_CDB;
    pReadCDTextData        : PREAD_TOC_PMA_ATIP_CDTEXT_DATA;
    aCDB                   : Array of Byte;
    i, j                   : Integer;
  begin
    {
    *  CD-Text initialisieren.
    }
    FillChar(FDrive[FActive].TableOfContentsCDText,
             SizeOf(FDrive[FActive].TableOfContentsCDText), $00);
    {
    *  Den Command Descriptor Block füllen.
    }
    ZeroMemory(@READ_TOC_PMA_ATIP_CDB, SizeOf(READ_TOC_PMA_ATIP_CDB));
    READ_TOC_PMA_ATIP_CDB.OperationCode    := SCSIOP_READ_TOC_PMA_ATIP;
    READ_TOC_PMA_ATIP_CDB.MSF              := 1;
    READ_TOC_PMA_ATIP_CDB.Format           := RF_CDTEXT;
    READ_TOC_PMA_ATIP_CDB.AllocationLength := SizeOf(TREAD_TOC_PMA_ATIP_DATA);
    {
    *  Den Command Descriptor Block übertragen.
    }
    SetLength(aCDB, 10);
    aCDB[0] := READ_TOC_PMA_ATIP_CDB.OperationCode;
    aCDB[1] := READ_TOC_PMA_ATIP_CDB.MSF and $01 shl 1;
    aCDB[2] := READ_TOC_PMA_ATIP_CDB.Format and $0F;
    aCDB[7] := HiByte(READ_TOC_PMA_ATIP_CDB.AllocationLength);
    aCDB[8] := LoByte(READ_TOC_PMA_ATIP_CDB.AllocationLength);
    {
    *  Befehl ausführen.
    }
    GetMem(pReadCDTextData, SizeOf(TREAD_TOC_PMA_ATIP_CDTEXT_DATA));
    Result := GET_SCSI_PASS_THROUGH_DIRECT(aDevice, aCDB, pReadCDTextData,
                                           SizeOf(TREAD_TOC_PMA_ATIP_CDTEXT_DATA));
    if Result then
    with FDrive[FActive].TableOfContentsCDText
    do begin
      DataLength := Swap(pReadCDTextData.Header.DataLength);
      {
      *  Prüfen, ob Daten folgen.
      *  Bei einer leeren Antwort ist der Wert wegen der Initialisierung 0.
      }
      if DataLength > 2
      then begin
        {
        *  Rohen Text übernehmen.
        }
        SetLength(Pack, (DataLength - 2) div 18);
        for i := 0 to ((DataLength - 2) div 18) - 1
        do begin
          {  Header  }
          for j := 0 to 3
          do Pack[i][j] := pReadCDTextData.Blocks[i].Header[j];
          {  Daten  }
          for j := 0 to 11
          do Pack[i][j + 4] := Ord(pReadCDTextData.Blocks[i].Data[j]);
          {  CRC  }
          for j := 0 to 1
          do Pack[i][j + 16] := pReadCDTextData.Blocks[i].CRC[j];
        end;
      end;
    end;
  end;
          

 

Demo, welche diese Funktion nutzt:

CD Text MMC (podCDTextMMC.7z - 314 kb) MD5 (1 kb). Stand: 11. August 2013