Home | Kontakt | Sitemap

Start

Über mich

Kontakt

Sitemap

Lizenz

Anleitungen

DVD, miniDVD

SVCD

Audio, Audio-CD (CD-DA)

AVI

Software

Von Freunden und Bekannten

Eigene Programme

Programmierung

Delphi

Lazarus

Delphi/Lazarus

Projekte

MPEG-1/2 Video

Optische Laufwerke

Audio-CD (CDDA)

Raspberry Pi Dashcam

Verschiedenes

MPEG 2 Schnitt

Project X

VCD Easy

Hardlinks

Windows

Links

Software

Projekte | Optische Laufwerke - MedienInformationen - CD Text (MMC)

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:

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

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.

 76543210
0CD-TEXT Data Length
1
2Beim CD-Text Format reserviert.
3
 CD-Text Descriptoren
0..17CD-Text Pack Data

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

Das CD-Text Pack Data Format:

ByteCD-Text Pack Data Format
0Header Feld ID1: Packtypindikator
1Header Feld ID2: Tracknummer
2Header Feld ID3: Packnummer
3Header Feld ID4: Blocknummer und Zeichenpositionindicator
4
..
15
Text Datenfelder Byte 0..11
16CRC Feld Byte 0 oder reserviert.
17CRC 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:

WertBeschreibungInhalt
$80Liste mit dem Titel des Albums (ID2 = $00) und
den Titeln der Tracks (ID2 = %01...$63).
ASCII
$81Liste mit den Namen der Interpreten.ASCII
$82Name des Texter (Songwriter)ASCII
$83Name des Komponisten (Composer)ASCII
$84Name des Arrangeurs (Arranger)ASCII
$85Nachricht vom Inhalteanbieter und/oder KünstlerASCII
$86DiscidentifikationinformationBinär
$87Genreidentifkation und GenreinformationBinär
$88Table of Content InformationBinär
$89Zweite Table of Content InformationBinär
$8AReserviert---
$8BReserviert---
$8CReserviert---
$8DNur für den Inhalteanbieter reserviert.?
$8EListe mit UPC/EAN Code des Albums und eventuell den ISRC Codes aller Tracks.ASCII
$8FGrößeninformation über den Block.Binär

Das vierte Headerbyte:

 76543210
DBCCBlocknummerZeichenposition

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.

01234567891011 121314151617
$80$00$00$00Mia.    Willk$DE 23
$80$00$01$0Commen  im Clu$EA 0F
$80$00$02$0Fb#0Kapit än#0Me$8A 7A
$80$02$03$02in Fre und#0Ma$26 C4
$80$03$04$02usen#0D u#0100 $8C 3C
$80$05$05$04Prozen t#0Magi$7A A7
$80$06$06$04sch#0De inetwe$87 15
$80$07$07$08gen#0Ve rfolge$0C B3
$80$08$08$08r#0Glüc ksster$BE 52
$80$09$09$0An#0Halt  Still$9E D3
$80$0A$0A$0A#0Die A ussich$71 ED
$80$0B$0B$0Bt#0#0#0#0#0 #0#0#0#0#0#0$18 BD
$81$00$0C$00Mia.#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$00383836393733 323132333200$C1 69
$8F$00$0F$0000010B030C02 000000000100$59 15
$8F$01$10$00000000000000 000311000000$65 5E
$8F$02$11$00000000000000 000000000000$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

CD ATIP > CD Text MMC > CD Text IOCTL