2 * FryingPan - Amiga CD/DVD Recording Software (User Interface and supporting Libraries only)
3 * Copyright (C) 2001-2011 Tomasz Wiszkowski Tomasz.Wiszkowski at gmail.com
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License
7 * as published by the Free Software Foundation; either version 2.1
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "Disc_CD_ROM.h"
23 Disc_CD_ROM::Disc_CD_ROM(Drive
*d
) : Disc(d
)
25 pReadCD
= new cmd_ReadCD(dio
);
26 pReadSub
= new cmd_ReadSubChannel(dio
);
31 Disc_CD_ROM::~Disc_CD_ROM()
41 void Disc_CD_ROM::Init()
45 const_cast<IOptItem
*>(GetContents())->setSectorSize(2352);
52 for (int i
=0; i
<GetContents()->getChildCount(); i
++)
54 const_cast<IOptItem
*>(GetContents()->getChild(i
))->setSectorSize(2352);
55 const_cast<IOptItem
*>(GetContents()->getChild(i
)->getChild(0))->setPreGapSize(150);
58 mcn
= pReadSub
->getMCN();
61 int Disc_CD_ROM::probeCDText()
65 TList
<String
*> *sa
= 0;
67 const IOptItem
*di
= 0;
69 rtc
= new cmd_ReadTOC(dio
);
72 _D(Lvl_Debug
, "Error while creating ReadTOC/CDText structure");
76 toc
= rtc
->GetCDText();
79 _D(Lvl_Debug
, "Disc does not contain CD-Text information");
84 sa
= toc
->GetTitles();
87 for (unsigned long i
=0; i
<=(unsigned)GetNumTracks(); i
++)
89 if ((s
= sa
->Get(i
))!=0)
94 di
= FindTrack(i
); // only first session may contain cd audio!
99 const_cast<IOptItem
*>(di
)->setCDTTitle(s
->Data());
107 sa
= toc
->GetPerformers();
110 for (unsigned long i
=0; i
<=(unsigned)GetNumTracks(); i
++)
112 if ((s
= sa
->Get(i
))!=0)
117 di
= FindTrack(i
); // only first session may contain cd audio!
122 const_cast<IOptItem
*>(di
)->setCDTArtist(s
->Data());
130 sa
= toc
->GetSongWriters();
133 for (unsigned long i
=0; i
<=(unsigned)GetNumTracks(); i
++)
135 if ((s
= sa
->Get(i
))!=0)
140 di
= FindTrack(i
); // only first session may contain cd audio!
145 const_cast<IOptItem
*>(di
)->setCDTLyrics(s
->Data());
155 sa
= toc
->GetComposers();
156 for (unsigned long i
=0; i
<=(unsigned)GetNumTracks(); i
++)
158 if ((s
= sa
->Get(i
))!=0)
163 di
= FindTrack(i
); // only first session may contain cd audio!
168 const_cast<IOptItem
*>(di
)->setCDTComposer(s
->Data());
178 sa
= toc
->GetArrangers();
179 for (unsigned long i
=0; i
<=(unsigned)GetNumTracks(); i
++)
181 if ((s
= sa
->Get(i
))!=0)
186 di
= FindTrack(i
); // only first session may contain cd audio!
191 const_cast<IOptItem
*>(di
)->setCDTDirector(s
->Data());
201 sa
= toc
->GetMessages();
202 for (unsigned long i
=0; i
<=(unsigned)GetNumTracks(); i
++)
204 if ((s
= sa
->Get(i
))!=0)
209 di
= FindTrack(i
); // only first session may contain cd audio!
214 const_cast<IOptItem
*>(di
)->setCDTMessage(s
->Data());
225 int Disc_CD_ROM::probeDataType()
230 // FIXME: data probing disabled
233 cmd_ReadHeader
*rh
= new cmd_ReadHeader(dio
);
234 const IOptItem
*item
;
238 for (int i
=1; i
; i
++)
245 * warning: ReadISRC REQUIRES USER SETTING
246 * as it is hell slow on drives that don't support it
249 isrc = pReadSub->getISRC(item->getItemNumber());
255 _D(Lvl_Debug, "Got valid ISRC!");
261 if (item
->getDataType() == Data_Mode1
)
263 EDataType t
= rh
->GetTrackType(item
->getStartAddress());
264 if (rh
->OpticalError() == ODE_OK
)
266 _D(Lvl_Info
, "Track %ld - track mode %ld", item
->getItemNumber(), t
);
267 const_cast<IOptItem
*>(item
)->setDataType(t
);
272 _D(Lvl_Info
, "%s: Finished track mode detection", (uint
)__PRETTY_FUNCTION__
);
274 _D(Lvl_Info
, "%s: all done", (uint
)__PRETTY_FUNCTION__
);
278 int Disc_CD_ROM::getSubChannelInfo(int32 pos
, uint8
&trk
, uint8
&idx
)
281 res
= pReadCD
->readCD(pos
, 1, sizeof(SUB_Q
), subq
, cmd_ReadCD::Flg_AllSubQ
);
285 trk
= subq
->getTrack();
286 idx
= subq
->getIndex();
287 _D(Lvl_Info
, "%s: trk %ld, idx %ld, ctl %ld, adr %ld, rel %06lx, abs %06lx",
288 (int)__PRETTY_FUNCTION__
,
300 int Disc_CD_ROM::probeSubChannel()
302 if (GetContents()->getChildCount() == 0)
305 #warning speed this shit up
308 SUB_Q *subq = new SUB_Q;
309 int32 cpos = 0; // this is a fixed value, tho most CD's won't be able to seek that far :P
313 int32 lpos = 0; // defaults :P
332 cpos = GetContents()->getEndAddress();
337 rcd.readCD(lpos, 1, sizeof(SUB_Q), subq, cmd_ReadCD::Flg_AllSubQ);
338 ltrk = subq->getTrack();
339 lidx = subq->getIndex();
349 if (cpos > GetContents()->getEndAddress())
351 cpos = GetContents()->getEndAddress();
352 if (fnd && dist == 1)
358 rcd.readCD(cpos, 1, sizeof(SUB_Q), subq, cmd_ReadCD::Flg_AllSubQ);
359 ctrk = subq->getTrack();
360 cidx = subq->getIndex();
362 if ((ltrk != ctrk) || (lidx != cidx))
377 trk = FindTrack(ltrk);
380 idx = const_cast<IOptItem*>(trk)->addChild();
381 idx->setStartAddress(lpos);
382 idx->setEndAddress(cpos-1);
383 idx->setItemNumber(lidx);
388 while (lpos != GetContents()->getEndAddress());
395 int Disc_CD_ROM::probeSubChannel()
397 for (int sn
=0; sn
<GetContents()->getChildCount(); sn
++)
399 for (int tn
=0; tn
<GetContents()->getChild(sn
)->getChildCount(); tn
++)
401 const IOptItem
*trak
= GetContents()->getChild(sn
)->getChild(tn
);
403 uint8 ctn
, cin
, ltn
, lin
;
404 int32 spos
, cpos
, epos
, dlta
;
407 // don't read subchannel data for blanks. it won't work.
411 // this is where we begin
412 spos
= trak
->getStartAddress();
414 _D(Lvl_Info
, "%s: Analysing track %ld (%ld - %ld, %ld blocks long)",
415 (int)__PRETTY_FUNCTION__
,
416 trak
->getItemNumber(),
417 trak
->getStartAddress(),
418 trak
->getEndAddress(),
419 trak
->getBlockCount());
421 while (spos
< trak
->getEndAddress())
423 // if this fails, we may be either reading wrong sector type or
424 // cd does not support command or maybe reading subq fails. whatever.
425 if (ODE_OK
!= getSubChannelInfo(spos
, ltn
, lin
))
428 // we always check at most the last sector.
429 epos
= trak
->getEndAddress();
434 // typical loop inside to find further indices.
435 while (ODE_OK
== getSubChannelInfo(cpos
, ctn
, cin
))
439 dlta
= (dlta
+ 1) >> 1;
441 if (ctn
!= ltn
) // track numbers do not match
442 break; // means we got shit man
443 if ((cin
== lin
) && (cpos
== epos
))
445 if ((cin
== lin
) && (done
))
451 cpos
= spos
> cpos
? spos
: cpos
;
452 cpos
= epos
< cpos
? epos
: cpos
;
455 _D(Lvl_Info
, "%s: Adding index %ld to track %ld from sector %ld to %ld", (int)__PRETTY_FUNCTION__
,
456 trak
->getItemNumber(),
460 indx
= const_cast<IOptItem
*>(trak
)->addChild();
461 indx
->setStartAddress(spos
);
462 indx
->setEndAddress(cpos
);
463 indx
->setItemNumber(lin
);
467 // this is true for very very special type of cd
468 if (trak
->getChildCount() == 0)
470 indx
= const_cast<IOptItem
*>(trak
)->addChild();
471 indx
->setFlags(DIF_RelativeSize
);
472 indx
->setStartAddress(0);
473 indx
->setDataBlockCount(-1);
474 indx
->setItemNumber(1);
475 _D(Lvl_Info
, "%s: Track empty or no indices read", (int)__PRETTY_FUNCTION__
);
484 int Disc_CD_ROM::CheckItemData(const IOptItem
*)
486 _D(Lvl_Info
, "Inserted disc is not writable");
490 int Disc_CD_ROM::RandomRead(const IOptItem
*i
, int32 first
, int32 count
, void* buff
)
501 _D(Lvl_Warning
, "No memory passed.");
504 if ((first
) < (i
->getStartAddress()))
506 _D(Lvl_Warning
, "First sector before starting address: wanted: %ld, min: %ld", first
, i
->getStartAddress());
507 return ODE_BadBlockNumber
;
509 if ((first
) > (i
->getEndAddress()))
511 _D(Lvl_Warning
, "First sector beyond ending address: wanted: %ld, max: %ld", first
, i
->getEndAddress());
512 return ODE_BadBlockNumber
;
514 if ((first
+count
) > (i
->getEndAddress()+1)) // first sector = last block in track, count = 1.
516 _D(Lvl_Warning
, "Last sector beyond ending address: wanted: %ld, size %ld; max: %ld", first
, count
, i
->getEndAddress());
517 return ODE_BadBlockNumber
;
520 switch (i
->getItemType())
524 flags
= cmd_ReadCD::Flg_Sync
| cmd_ReadCD::Flg_12BHeader
| cmd_ReadCD::Flg_ECC
;
526 flags
|= cmd_ReadCD::Flg_UserData
;
531 int err
= pReadCD
->readCD(first
, count
, i
->getSectorSize(), buff
, flags
);
535 int Disc_CD_ROM::EndTrackWrite(const IOptItem
*)
537 return ODE_IllegalCommand
;
540 void Disc_CD_ROM::FillDiscSpeed(DiscSpeed
&spd
)
543 spd
.i
= ((int32
)10*spd
.kbps
+882)/1764; // we need to round up the speed. 882 = 1764/2, so it's a halve.
546 uint32
Disc_CD_ROM::probeFreeDBID()
548 cmd_ReadTOC
rtc(dio
);
549 TOC_PrimitiveTOC
*toc
= 0;
550 TOC_PrimitiveEntry
*te1
= 0;
551 TOC_PrimitiveEntry
*te2
= 0;
558 toc
= rtc
.GetTOC(true);
562 for (int i
=1; i
<=toc
->GetNumTracks(); i
++)
564 te1
= toc
->FindTOCEntry(i
);
565 id1
+= sumDigits(te1
->GetMin()*60 + te1
->GetSec());
568 te1
= toc
->FindTOCEntry(1);
569 te2
= toc
->FindTOCEntry(0xAA);
570 id2
= (60 * te2
->GetMin() + te2
->GetSec()) - (60 * te1
->GetMin() + te1
->GetSec());
571 dbid
= ((id1
& 0xff) << 24) | ((id2
& 0xffff) << 8) | (toc
->GetNumTracks());
578 int Disc_CD_ROM::sumDigits(int32 val
)