Get CD audio track frame?

Everything else that doesn't fall into one of the other PB categories.
User avatar
GeoTrail
Addict
Addict
Posts: 2799
Joined: Fri Feb 13, 2004 12:45 am
Location: Bergen, Norway
Contact:

Post by GeoTrail »

Yes that is the idea anyways, I'm just hoping it'll work though ;)

If you make a working version you can test it and compare it with the result from this app which is working.

DiscId calculator
http://webplaza.pt.lu/public/vigatol/discidcalc/

Here's a screenshot:
Image
I Stepped On A Cornflake!!! Now I'm A Cereal Killer!
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

That's what I'm doing right now. :)

I'll be gone for a few hours but will continue later tonight. ;)
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

Ok GeoTrail, here's what I have come up with so far. It may need some cleaning up, but I'll have to do that later tomorrow. ;)

I checked 3 different audio cd's and compared my DiscID with that of the app you pointed to, and all 3 DiscID's matched. :)

Code: Select all

#Win_Main = 0
#Button_0 = 0
#ListIcon_0 = 1
#Text_0 = 2
#Track = 22
#TrackStart = 36
#TrackLength = 40

Structure toc 
  min.l 
  sec.l 
  frame.l 
EndStructure 

Dim cdtoc.toc(100) 
Dim trackNum$(99)

Procedure.l read_cdtoc_from_drive(files2read$)
  trackCount.l = 0
  trackNum.l = 0
  ; --> count tracks
  While files2read$ 
    trackNum$(trackCount) = files2read$
    files2read$ =  NextSelectedFileName() 
    trackCount + 1
  Wend
  ; --> Sort the file names in ascending order
  SortArray(trackNum$(), 0)
  ; --> Our file names are at the end of our array
  ; --> with null filenames being first after sorting
  ; --> do the math to get the first .cda file (Track01.cda)
  For track = 100 - trackCount To 99
    ; --> Open file for reading
    ReadFile(0, trackNum$(track))
    ; --> Seek to track byte
    FileSeek(#Track)
    track$ = RSet(Str(ReadByte()&$FF), 2, "0")
    ; --> Seek to track start info
    FileSeek(#TrackStart)
    ; --> Add leading zeros to track start info
    trackBeginFrame$ = RSet(Str(ReadByte()&$FF), 2, "0")
    trackBeginSeconds$ = RSet(Str(ReadByte()&$FF), 2, "0")
    trackBeginMinutes$ = RSet(Str(ReadByte()&$FF), 2, "0")
    ; --> Seek to track length info
    FileSeek(#TrackLength)
    ; --> Add leading zeros to track length info
    trackLengthFrame$ = RSet(Str(ReadByte()&$FF), 2, "0")
    trackLengthSeconds$ = RSet(Str(ReadByte()&$FF), 2, "0")
    trackLengthMinutes$ = RSet(Str(ReadByte()&$FF), 2, "0")
    ; --> Close file
    CloseFile(0)
    ; --> Do math to get track end info
    trackEndMinutes = Val(trackBeginMinutes$) + Val(trackLengthMinutes$)
    If trackEndMinutes >= 60
      trackEndMinutes - 60
    EndIf
    ; --> 60 seconds = 1 minute so make adjustments as needed
    trackEndSeconds = Val(trackBeginSeconds$) + Val(trackLengthSeconds$)
    If trackEndSeconds >= 60
      trackEndSeconds - 60
      trackEndMinutes + 1
    EndIf
    ; --> 75 frames = 1 second so make adjustments as needed
    trackEndFrames = Val(trackBeginFrame$) + Val(trackLengthFrame$) 
    If trackEndFrames >= 75
      trackEndFrames - 75
      trackEndSeconds + 1
    EndIf
    ; --> Fill track end info with 0's
    trackEndFrames$ = RSet(Str(trackEndFrames), 2, "0")
    trackEndSeconds$ = RSet(Str(trackEndSeconds), 2, "0")
    trackEndMinutes$ = RSet(Str(trackEndMinutes), 2, "0")
    ; --> Fill in the cdtoc for returning DiscID
    cdtoc(trackNum)\min = Val(trackBeginMinutes$)
    cdtoc(trackNum)\sec = Val(trackBeginSeconds$)
    cdtoc(trackNum)\frame = Val(trackBeginFrame$)
    trackNum + 1
    ; --> Add info to ListIconGadget
    AddGadgetItem(#ListIcon_0, -1, track$ + Chr(10) + trackBeginMinutes$ + ":" + trackBeginSeconds$ + "." + trackBeginFrame$ + Chr(10) + trackLengthMinutes$ + ":" + trackLengthSeconds$ + "." + trackLengthFrame$ + Chr(10) + trackEndMinutes$ + ":" + trackEndSeconds$ + "." + trackEndFrames$)
    files2read$ = NextSelectedFileName() 
  Next track
  ; --> This is the lead out
  cdtoc(trackNum)\min = Val(trackEndMinutes$)
  cdtoc(trackNum)\sec = Val(trackEndSeconds$)
  cdtoc(trackNum)\frame = Val(trackEndFrames$)
  ProcedureReturn trackCount
EndProcedure

Procedure.l cddb_sum(n) 
  ret.l = 0 
  While n > 0 
    ret = ret + (n % 10) 
    n = n / 10 
  Wend 
  ProcedureReturn ret 
EndProcedure 

Procedure.s cddb_discid(tot_trks) 
  t.l = 0 
  n.l = 0 
  i.l = 0 
  While i < tot_trks 
    n + cddb_sum((cdtoc(i)\min * 60) + cdtoc(i)\sec) 
    i+1 
  Wend 
  t = ((cdtoc(tot_trks)\min * 60) + cdtoc(tot_trks)\sec) - ((cdtoc(0)\min * 60) + cdtoc(0)\sec) 
  Debug t
  ProcedureReturn Hex(n % $FF << 24 | t << 8 | tot_trks)
EndProcedure 
ofPattern$ = "Audio (*.cda)|*.cda"
; ***********************************
; --> Change path to your cdrom drive
cdromDrive$ - "F:\"
; ***********************************
If OpenWindow( #Win_Main, 10, 10, 370, 400, #PB_Window_SystemMenu | #PB_Window_ScreenCentered, "Read .CDA") And CreateGadgetList(WindowID(#Win_Main))
  ButtonGadget(#Button_0, 5, 5, 100, 20, "Select CDA Files")
  TextGadget(#Text_0, 130, 10, 200, 20, "DiscID: ")
  HideGadget(#Text_0, 1)
  ListIconGadget(#ListIcon_0, 5, 35, 360, 360, "Track", 50, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection)
  AddGadgetColumn(#ListIcon_0, 1, "Start", 100)
  AddGadgetColumn(#ListIcon_0, 2, "Duration", 100)
  AddGadgetColumn(#ListIcon_0, 3, "End", 100)
  Repeat
    event = WaitWindowEvent()
    Select event
      Case #PB_EventGadget
        Select EventGadgetID()
          Case #Button_0
            SetGadgetText(#Text_0, "")
            HideGadget(#Text_0, 1)
            cdaFiles$ = OpenFileRequester("Select .CDA files to read", cdromDrive$, ofPattern$, 0, #PB_Requester_MultiSelection)
            If cdaFiles$ <> ""
              serial$ = ""
              tot_trks = read_cdtoc_from_drive(cdaFiles$)
              SetGadgetText(#Text_0, "DiscID: " + cddb_discid(tot_trks))
              HideGadget(#Text_0, 0)
            EndIf
        EndSelect
    EndSelect
  Until event = #PB_Event_CloseWindow
EndIf
End
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
User avatar
GeoTrail
Addict
Addict
Posts: 2799
Joined: Fri Feb 13, 2004 12:45 am
Location: Bergen, Norway
Contact:

Post by GeoTrail »

Wow, great work Sparkie.
Maybe you could change the code abit so it will autodetect the cd drive and automatically add all audio files if there are any?

Anyways, great work. I was thinking of posting that to the freedb.org website but since you're the one who did the hard work that is up to you :)
I Stepped On A Cornflake!!! Now I'm A Cereal Killer!
traumatic
PureBasic Expert
PureBasic Expert
Posts: 1661
Joined: Sun Apr 27, 2003 4:41 pm
Location: Germany
Contact:

Post by traumatic »

Ok, I see you already got what you wanted, however I continued
playing around with ASPI and found out why it didn't work for
you. If you're using the Adaptec drivers, make sure you have
the following registry entries:

Code: Select all

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ASPI32\Parameters] 
"ExcludeMiniports"="" 

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ASPI32]
"ErrorControl"=dword:00000001
"Start"=dword:00000002
"Type"=dword:00000001
Alternatively I found the Nero-ASPI to work flawlessly on all
systems (no installation, just copying).

If somebody's still interested in an ASPI-way of reading the
TOC, let me know.
Good programmers don't comment their code. It was hard to write, should be hard to read.
User avatar
GeoTrail
Addict
Addict
Posts: 2799
Joined: Fri Feb 13, 2004 12:45 am
Location: Bergen, Norway
Contact:

Post by GeoTrail »

Thanks for your time and effort traumatic.
I got your app working now btw, I installed some older version of the ASPI and that seemed to solve many problems on this end :)
I Stepped On A Cornflake!!! Now I'm A Cereal Killer!
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

GeoTrail wrote:Maybe you could change the code abit so it will autodetect the cd drive and automatically add all audio files if there are any?
I'm planning on cleaning and optimizing the code this week. I also plan to add the ASPI version as well. Once it's done and working flawlessly, feel free to send it to freedb.org. 8)
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
User avatar
GeoTrail
Addict
Addict
Posts: 2799
Joined: Fri Feb 13, 2004 12:45 am
Location: Bergen, Norway
Contact:

Post by GeoTrail »

Cool, but I will put your name in the credits, afterall, you got the thing working :)
Credits where credits due you know
I Stepped On A Cornflake!!! Now I'm A Cereal Killer!
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

That works for me :)
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
traumatic
PureBasic Expert
PureBasic Expert
Posts: 1661
Joined: Sun Apr 27, 2003 4:41 pm
Location: Germany
Contact:

Post by traumatic »

Just a side note:
Calculating the cddb or freedb disc-IDs by just using the .cda only works with
true redbook Audio-CDs. For everything else (mixed mode/CD extra) you'll
have to use ASPI/SPTI
Good programmers don't comment their code. It was hard to write, should be hard to read.
User avatar
GeoTrail
Addict
Addict
Posts: 2799
Joined: Fri Feb 13, 2004 12:45 am
Location: Bergen, Norway
Contact:

Post by GeoTrail »

Yeah that's true.
But the code Sparkie made should work in Linux too with some tweaking, don't you think?
I Stepped On A Cornflake!!! Now I'm A Cereal Killer!
traumatic
PureBasic Expert
PureBasic Expert
Posts: 1661
Joined: Sun Apr 27, 2003 4:41 pm
Location: Germany
Contact:

Post by traumatic »

.cda files are 'generated' by windows - they are not part of the actual cd data.
I don't know how linux behaves in this respect but I wouldn't be surprised if
this approach doesn't work at all on linux.

Just drop an audio-CD into your drive and tell us what linux says ;)
Good programmers don't comment their code. It was hard to write, should be hard to read.
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

Thanks traumatic :)

That's why I want to add the ASPI routine to my app. It will check for cd data type and only use the .cda routine when it's applicable. The .cda routine will be sort of a backup to the ASPI. This gives the possibilty to generate a DiscId if the user doesn't have/want the WNASPI.DLL installed.

@GeoTrail - This will probably take me more than a few days to complete. ;)
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
User avatar
GeoTrail
Addict
Addict
Posts: 2799
Joined: Fri Feb 13, 2004 12:45 am
Location: Bergen, Norway
Contact:

Post by GeoTrail »

@traumatic, yeah I'm gonna do that right now, haven't even thought about that ;)

@Sparkie, no worries m8. Take your time :)
I Stepped On A Cornflake!!! Now I'm A Cereal Killer!
traumatic
PureBasic Expert
PureBasic Expert
Posts: 1661
Joined: Sun Apr 27, 2003 4:41 pm
Location: Germany
Contact:

Post by traumatic »

Sparkie wrote:@GeoTrail - This will probably take me more than a few days to complete. ;)
This may shorten your work:

Code: Select all

Structure TOCTRACK
  Reserved.b
  CTL.b                 ; indicates the attributes of the track
  ADR.b                 ; type of information encoded in the QSub-channel of the block
  trackNumber.b         ; Track Number, 1 based. $AA ~ start of lead-out
  Reserved2.b
  addr.b[4]             ; adress of first block or LBA of track start
EndStructure

Structure TOC
  TOCLength.w           ; size of TOC
  firstTrack.b          ; first track number
  lastTrack.b           ; last track before lead-out
  tracks.TOCTRACK[100]  ; infos on each track
EndStructure

;
; ReadTOC()
;
Procedure.l ReadTOC(adapter.b, target.b, lun.b, *toc.TOC)
  srbExec.SRB_ExecSCSICmd
  
  hEventSRB.l = CreateEvent_(#NULL, #TRUE, #FALSE, #NULL)
  
  ZeroMemory_(@srbExec, SizeOf(SRB_ExecSCSICmd))
  srbExec\SRB_Cmd        = #SC_EXEC_SCSI_CMD
  srbExec\SRB_HaId       = adapter
  srbExec\SRB_Target     = target
  srbExec\SRB_Lun        = lun
  srbExec\SRB_Flags      = #SRB_DIR_IN | #SRB_EVENT_NOTIFY
  srbExec\SRB_BufLen     = $324
  srbExec\SRB_BufPointer = *toc
  srbExec\SRB_SenseLen   = $0E
  srbExec\SRB_CDBLen     = $0A
  srbExec\SRB_PostProc   = hEventSRB
  srbExec\CDBByte[0]     = $43 
  srbExec\CDBByte[7]     = $03
  srbExec\CDBByte[8]     = $24
  
  ResetEvent_(hEventSRB)
  status = CallCFunctionFast(*SendASPI32Command, @srbExec)
  
  If status = #SS_PENDING
    WaitForSingleObject_(hEventSRB, 4000)
  EndIf
  
  CloseHandle_(hEventSRB)
  
  If srbExec\SRB_Status <> #SS_COMP
    ; handle error here
    ProcedureReturn #SS_ERR
  EndIf
  
	ProcedureReturn #SS_COMP
EndProcedure
*SendASPI32Command = IsFunction(handleToYourDllOpenedWithOpenLibrary, "SendASPI32Command")

...and be sure to "Test Unit Ready" to see if a CD is present ;)
Good programmers don't comment their code. It was hard to write, should be hard to read.
Post Reply