...... // type TTrackRec = record Group: string; Title: Cardinal; TitleStr: string; Artist: Cardinal; ArtistStr: string; Album: Cardinal; AlbumStr: string; TrkNum: Cardinal; TrkLength: Cardinal; end; type TStringRec = record Index: Cardinal; StrType: string; Str: string; end; // var DiscTracks: array[1..2048] of TTrackRec; DiscStrings: array[1..4096] of TStringRec; ..... //================================================================ // Useful Utilities //================================================================ // // procedure to remove #0 padding characters from strings // procedure RemoveNullCharacters(var s: String); var i, j: Integer; begin j := 0; for i := 1 to Length(s) do if s[i] <> #0 then begin Inc(j); s[j] := s[i]; end; if j < Length(s) then SetLength(s, j); end; // // function to convert two-bye word to integer value // function IntPower(const N, k: cardinal): cardinal; inline; begin Result:= (256 * N) + k; end; // // functions to convert seconds to string format hh:mm:ss // function SecsToTimeStr(const Secs: Integer; const LeadingZero: Boolean = False): String; begin if Secs >= SecsPerHour then begin if LeadingZero then Result := FormatDateTime('hh:nn:ss', Secs / SecsPerDay) else Result := FormatDateTime('h:n:ss', Secs / SecsPerDay) end else begin if LeadingZero then Result := FormatDateTime('nn:ss', Secs / SecsPerDay) else Result := FormatDateTime('n:ss', Secs / SecsPerDay) end; end; //================================================================ procedure TfrmHiMDMain.ReadTrkFileAlt(Sender: TObject); // // This method reads the the string table and track info tables into // arrays of reords, then reads the string arrays to fill out // the track data. Track info records are not necessarity in playing // order, so the play order table is read to write them into the // in-memory current data table. Finally the group table is read to // get the disc title (if there is one) and the group names and tracks // and that data is written to the in-memory current data table. // // This code derives all of its data from the tables in the // track-index file. On the other hand it is pretty slow and // requires lots of separate iterations through the track info file, // and through the in-memory database. With my sledge-hammer // programming style, it's pretty slow. // var F: File; strbuf: array[0..15] of byte; infobuf: array[0..79] of byte; grpbuf: array[0..7] of byte; tkbuf: array[0..1] of byte; tmp, msg: string; track, artist, album, group: boolean; // i, j, k, t, d, cont, gstart, gend, gcount, numoftracks, recnum: Integer; m: cardinal; begin actClearMemoryExecute(Self); edTRKFile.Text := FileOpen.Dialog.FileName; lboxGroups.Clear; //<-- get rid of 'No Disc In Memory' //memTextData.Clear; AssignFile(F, edTRKfile.Text); try Reset(F, 1); // track := false; artist := false; album := false; group := false; // tmp:= ''; // OldCursor := Screen.Cursor; Screen.Cursor:= crHourGlass; // k := 0; // tracks index into string table cont := 0; // // skip opening block (16385 * 16 = 262160 = #40010 = offset // for i := 1 to 16385 do BlockRead(F, strbuf, 16); // // start processing data blocks // lblMessageRed.Caption := 'beginning to read string table...'; repeat BlockRead(F, strbuf, 16); inc(k); // we have to keep track of the entry number because // this is what is referenced in the track info table // // read first 13 bytes // if (ord(strbuf[14]) shr 4) = 8 then begin track := true; for i := 1 to 13 do tmp := tmp + char(strbuf[i]); end else if (ord(strbuf[14]) shr 4) = 9 then begin artist := true; for i := 1 to 13 do tmp := tmp + char(strbuf[i]); end else if (ord(strbuf[14]) shr 4) = 10 then begin album := true; for i := 1 to 13 do tmp := tmp + char(strbuf[i]); end else if (ord(strbuf[14]) shr 4) = 12 then begin group := true; for i := 1 to 13 do tmp := tmp + char(strbuf[i]); end; //for i := 1 to 13 do tmp := tmp + char(strbuf[i]); // // if there a continuation keep reading // lblMessageRed.Caption := 'checking for continuation...'; if (ord(strbuf[15]) > 0) and ((ord(strbuf[14]) shl 4) > 0) and (char(strbuf[0]) <> #00) // make sure we don't loop after last record then repeat BlockRead(F, strbuf, 16); inc(cont); for i := 0 to 13 do tmp := tmp + char(strbuf[i]); until (ord(strbuf[14]) = 16) and (ord(strbuf[15]) = 0); // // routine to write data to a record and to memo // lblMessageRed.Caption := 'writing data to stringlist...'; msg := tmp; RemoveNullCharacters(msg); // if track then DiscStrings[k].StrType := 'track' else if artist then DiscStrings[k].StrType := 'artist' else if album then DiscStrings[k].StrType := 'album' else if group then DiscStrings[k].StrType := 'group'; // DiscStrings[k].Index := k; DiscStrings[k].str := msg; memTextData.Lines.Add(inttostr(DiscStrings[k].Index) + // entry number ' - ' + DiscStrings[k].StrType + // entry type ' - ' + DiscStrings[k].Str); // entry k := k + cont; // adjust for continuation count cont := 0; // clear continuation count // // blank other values // tmp:= ''; track := false; artist := false; album := false; group := false; // // loop // until char(strbuf[0]) = #0; // finally lblMessageRed.Caption := 'finishing string table...'; CloseFile(F); end; //try // // for k := 1 to 2048 do begin DiscTracks[k].Group := 'No Group'; DiscTracks[k].Title := 0; DiscTracks[k].TitleStr := ''; DiscTracks[k].Artist := 0; DiscTracks[k].ArtistStr := ''; DiscTracks[k].Album := 0; DiscTracks[k].AlbumStr := ''; DiscTracks[k].TrkNum := 0; DiscTracks[k].TrkLength := 0; end; // memTrackInfo.Clear; // try Reset(F, 1); // tmp:= ''; // // skip opening block (409 * 80 = 32720 = #07FD0 = offset - #00020 // for i := 1 to 409 do BlockRead(F, infobuf, 80); // BlockRead(F, infobuf, 48); // to get up 40 #08000 // // start processing data blocks // lblMessageRed.Caption := 'beginning to read track info table...'; // // read first block for entry count // BlockRead(F, infobuf, 80); m := IntPower(infobuf[38],infobuf[39]); // for i := 0 to m - 2 do begin // // loop to write to memo fill in strings in records // BlockRead(F, infobuf, 80); // DiscTracks[i + 1].Title := IntPower(infobuf[8],infobuf[9]); DiscTracks[i + 1].Artist := IntPower(infobuf[10],infobuf[11]); DiscTracks[i + 1].Album := IntPower(infobuf[12],infobuf[13]); DiscTracks[i + 1].TrkNum := IntPower(infobuf[38],infobuf[39]); DiscTracks[i + 1].TrkLength := IntPower(infobuf[40],infobuf[41]); memTrackinfo.Lines.Add(Inttostr(DiscTracks[i + 1].title) + ' - '+ Inttostr(DiscTracks[i + 1].Artist) + ' - '+ Inttostr(DiscTracks[i + 1].Album) + ' - '+ Inttostr(DiscTracks[i + 1].TrkNum) + ' - '+ Inttostr(DiscTracks[i + 1].TrkLength)); // for d := 1 to 4096 do if DiscStrings[d].index = DiscTracks[i + 1].Title then begin tmp := 'Title: ' + DiscStrings[d].Str + ' - '; DiscTracks[i + 1].TitleStr := DiscStrings[d].Str; break; end; // for d := 0 to 4095 do if DiscStrings[d].index = DiscTracks[i + 1].Artist then begin tmp := tmp + 'Artist: ' + DiscStrings[d].Str + ' - '; DiscTracks[i + 1].ArtistStr := DiscStrings[d].Str; break; end; // for d := 0 to 4095 do if DiscStrings[d].index = DiscTracks[i + 1].Album then begin tmp := tmp + 'Album: ' + DiscStrings[d].Str + ' - '; DiscTracks[i + 1].AlbumStr := DiscStrings[d].Str; break; end; // tmp := tmp + ' Track# ' + inttostr(DiscTracks[i + 1].TrkNum) + ' - ' + SecsToTimeStr(DiscTracks[i + 1].TrkLength); // // memTrackInfo.Lines.Add(tmp); // end; finally lblMessageRed.Caption := 'finishing with track info table...'; CloseFile(F); // end; //try // // rite partial records to memory table according to the // 'play order table' at 0x00100 // try Reset(F, 1); // tmp:= ''; // // skip opening block (128 * 2 = 256 = #00100 // for i := 1 to 128 do BlockRead(F, tkbuf, 2); // // lblMessageRed.Caption := 'beginning to process the play order table ...'; // // process the tracks in order // BlockRead(F, tkbuf, 2); // // read first record and retrieve disc name // numoftracks := IntPower(tkbuf[0],tkbuf[1]); for i := 1 to numoftracks do begin memTracks.append; BlockRead(F, tkbuf, 2); recnum := IntPower(tkbuf[0],tkbuf[1]); memTracksTracknum.Value := DiscTracks[recnum].TrkNum; memTracksGroup.AsString := '--No Group--'; memTracksTrack.AsString := DiscTracks[recnum].TitleStr; memTracksLength.AsString := SecsToTimeStr(DiscTracks[recnum].TrkLength); memTracksArtist.AsString := DiscTracks[recnum].ArtistStr; memTracksAlbum.AsString := DiscTracks[recnum].AlbumStr; memTracks.Post; end; finally lblMessageRed.Caption := 'finishing with play order table...'; CloseFile(F); end; //try // // read disc title and groups from group table // try Reset(F, 1); // tmp:= ''; // // skip opening block (1056 * 8 = 8448 = #02100 // for i := 1 to 1056 do BlockRead(F, grpbuf, 8); // // process the group table entries // lblMessageRed.Caption := 'beginning to process the group table ...'; // // read first record and retrieve disc name // Blockread(F, grpbuf, 8); if DiscStrings[IntPower(grpbuf[4],grpbuf[5])].Str <> '' then edDiscName.Text := DiscStrings[IntPower(grpbuf[4],grpbuf[5])].Str else edDiscName.Text := '--No Title--';; // memTracks.First; for i := 1 to memTracks.RecordCount do begin memTracks.Edit; memTracks.FieldByName('Disc').asstring := edDiscName.text; memTracks.post; memTracks.Next; end; // // loop through balance of 255 records // looking for group START, END and name memTracks.First; repeat BlockRead(F, grpbuf, 8); gstart := IntPower(grpbuf[0],grpbuf[1]); gend := IntPower(grpbuf[2],grpbuf[3]); if (gstart = 0) and (gend = 0) then break; // catch the end gcount := gend - gstart + 1; tmp := DiscStrings[IntPower(grpbuf[4],grpbuf[5])].Str; // // for each record // lboxGroups.items.Add(tmp); memTrackInfo.Lines.Add(tmp + ' from ' + inttostr(gstart) + ' to ' + inttostr(gend)); // memTracks.First; for i := 1 to gstart - 1 do memTracks.Next; for i := 1 to gcount do begin memTracks.Edit; memTracksGroup.AsString := tmp; memTracks.Post; memTracks.Next; end; // if start is empty then break loop until IntPower(grpbuf[0],grpbuf[1]) = 0; // memTracks.First; finally lblMessageRed.Caption := 'finishing with group table...'; CloseFile(F); // end; // insert disc name into current data edTitle.Clear; edTitle.Text := edDiscName.Text; edPlayList.Clear; DiscInMemory := true; Screen.Cursor := OldCursor; // // remnant code // for i := 0 to lboxGroups.Items.Count - 1 do edPlayList.Lines.add(lboxGroups.items[i]); lblMessageRed.Caption := ''; // // lboxGroups.ItemIndex := 0; lboxGroupsClick(Self); //pagesMD.ActivePage := tabMemo; pagesMD.ActivePage := tabLabel; end;