Page 3 of 4
Posted: Sun Apr 10, 2005 4:32 pm
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:

Posted: Sun Apr 10, 2005 4:39 pm
by Sparkie
That's what I'm doing right now.
I'll be gone for a few hours but will continue later tonight.

Posted: Sun Apr 10, 2005 11:12 pm
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
Posted: Mon Apr 11, 2005 9:00 am
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

Posted: Mon Apr 11, 2005 10:42 am
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.
Posted: Mon Apr 11, 2005 11:43 am
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

Posted: Mon Apr 11, 2005 12:33 pm
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.

Posted: Mon Apr 11, 2005 12:39 pm
by GeoTrail
Cool, but I will put your name in the credits, afterall, you got the thing working

Credits where credits due you know
Posted: Mon Apr 11, 2005 12:45 pm
by Sparkie
That works for me

Posted: Mon Apr 11, 2005 1:05 pm
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
Posted: Mon Apr 11, 2005 1:20 pm
by GeoTrail
Yeah that's true.
But the code Sparkie made should work in Linux too with some tweaking, don't you think?
Posted: Mon Apr 11, 2005 1:25 pm
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

Posted: Mon Apr 11, 2005 1:26 pm
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.

Posted: Mon Apr 11, 2005 1:33 pm
by GeoTrail
@traumatic, yeah I'm gonna do that right now, haven't even thought about that
@Sparkie, no worries m8. Take your time

Posted: Mon Apr 11, 2005 1:43 pm
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
