forgotten commit. disabled until egl is adapted.
[AROS-Contrib.git] / FryingPan / Optical / Disc_CD_ROM.cpp
blob17c719ad16e5c53ed041630f1a6fa72141cd7113
1 /*
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
4 *
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.
9 *
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.
20 #include "Headers.h"
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);
27 mcn = 0;
28 subq = new SUB_Q;
31 Disc_CD_ROM::~Disc_CD_ROM()
33 delete pReadCD;
34 delete pReadSub;
35 if (mcn)
36 delete mcn;
37 if (subq)
38 delete subq;
41 void Disc_CD_ROM::Init()
43 Disc::Init();
45 const_cast<IOptItem*>(GetContents())->setSectorSize(2352);
47 probeCDText();
48 probeDataType();
49 probeSubChannel();
50 probeFreeDBID();
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()
63 cmd_ReadTOC *rtc = 0;
64 TOC_CDText *toc = 0;
65 TList<String*> *sa = 0;
66 String *s = 0;
67 const IOptItem *di = 0;
69 rtc = new cmd_ReadTOC(dio);
70 if (!rtc)
72 _D(Lvl_Debug, "Error while creating ReadTOC/CDText structure");
73 return 0;
76 toc = rtc->GetCDText();
77 if (!toc)
79 _D(Lvl_Debug, "Disc does not contain CD-Text information");
80 delete rtc;
81 return 0;
84 sa = toc->GetTitles();
85 if (sa)
87 for (unsigned long i=0; i<=(unsigned)GetNumTracks(); i++)
89 if ((s = sa->Get(i))!=0)
91 if (s->Length())
93 if (i)
94 di = FindTrack(i); // only first session may contain cd audio!
95 else
96 di = FindSession(1);
97 if (di)
99 const_cast<IOptItem*>(di)->setCDTTitle(s->Data());
104 delete sa;
107 sa = toc->GetPerformers();
108 if (sa)
110 for (unsigned long i=0; i<=(unsigned)GetNumTracks(); i++)
112 if ((s = sa->Get(i))!=0)
114 if (s->Length())
116 if (i)
117 di = FindTrack(i); // only first session may contain cd audio!
118 else
119 di = FindSession(1);
120 if (di)
122 const_cast<IOptItem*>(di)->setCDTArtist(s->Data());
127 delete sa;
130 sa = toc->GetSongWriters();
131 if (sa)
133 for (unsigned long i=0; i<=(unsigned)GetNumTracks(); i++)
135 if ((s = sa->Get(i))!=0)
137 if (s->Length())
139 if (i)
140 di = FindTrack(i); // only first session may contain cd audio!
141 else
142 di = FindSession(1);
143 if (di)
145 const_cast<IOptItem*>(di)->setCDTLyrics(s->Data());
150 delete sa;
153 if (sa)
155 sa = toc->GetComposers();
156 for (unsigned long i=0; i<=(unsigned)GetNumTracks(); i++)
158 if ((s = sa->Get(i))!=0)
160 if (s->Length())
162 if (i)
163 di = FindTrack(i); // only first session may contain cd audio!
164 else
165 di = FindSession(1);
166 if (di)
168 const_cast<IOptItem*>(di)->setCDTComposer(s->Data());
173 delete sa;
176 if (sa)
178 sa = toc->GetArrangers();
179 for (unsigned long i=0; i<=(unsigned)GetNumTracks(); i++)
181 if ((s = sa->Get(i))!=0)
183 if (s->Length())
185 if (i)
186 di = FindTrack(i); // only first session may contain cd audio!
187 else
188 di = FindSession(1);
189 if (di)
191 const_cast<IOptItem*>(di)->setCDTDirector(s->Data());
196 delete sa;
199 if (sa)
201 sa = toc->GetMessages();
202 for (unsigned long i=0; i<=(unsigned)GetNumTracks(); i++)
204 if ((s = sa->Get(i))!=0)
206 if (s->Length())
208 if (i)
209 di = FindTrack(i); // only first session may contain cd audio!
210 else
211 di = FindSession(1);
212 if (di)
214 const_cast<IOptItem*>(di)->setCDTMessage(s->Data());
219 delete sa;
221 if (rtc) delete rtc;
222 return 1;
225 int Disc_CD_ROM::probeDataType()
228 * disabled for now
230 // FIXME: data probing disabled
231 return 1;
233 cmd_ReadHeader *rh = new cmd_ReadHeader(dio);
234 const IOptItem *item;
235 //SUB_ISRC *isrc;
238 for (int i=1; i; i++)
240 item = FindTrack(i);
241 if (0 == item)
242 break;
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());
251 if (isrc)
253 if (isrc->isValid())
255 _D(Lvl_Debug, "Got valid ISRC!");
257 delete 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__);
273 delete rh;
274 _D(Lvl_Info, "%s: all done", (uint)__PRETTY_FUNCTION__);
275 return 1;
278 int Disc_CD_ROM::getSubChannelInfo(int32 pos, uint8 &trk, uint8 &idx)
280 int res;
281 res = pReadCD->readCD(pos, 1, sizeof(SUB_Q), subq, cmd_ReadCD::Flg_AllSubQ);
283 if (res == ODE_OK)
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__,
289 subq->getTrack(),
290 subq->getIndex(),
291 subq->getCtl(),
292 subq->getAdr(),
293 subq->getRelPos(),
294 subq->getAbsPos());
296 return res;
300 int Disc_CD_ROM::probeSubChannel()
302 if (GetContents()->getChildCount() == 0)
303 return 0;
305 #warning speed this shit up
307 cmd_ReadCD rcd(dio);
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
310 uint8 cidx = 0;
311 uint8 ctrk = 0;
313 int32 lpos = 0; // defaults :P
314 uint8 lidx = 0; //
315 uint8 ltrk = 1; //
317 int32 dist = 0;
318 bool fnd;
320 const IOptItem *trk;
321 IOptItem *idx;
323 trk = FindTrack(1);
324 if (trk->isBlank())
326 delete subq;
327 return 0;
332 cpos = GetContents()->getEndAddress();
333 dist = cpos - lpos;
334 if (!dist)
335 break;
337 rcd.readCD(lpos, 1, sizeof(SUB_Q), subq, cmd_ReadCD::Flg_AllSubQ);
338 ltrk = subq->getTrack();
339 lidx = subq->getIndex();
341 fnd = false;
345 dist = (dist+1)>>1;
346 if (!dist)
347 break;
349 if (cpos > GetContents()->getEndAddress())
351 cpos = GetContents()->getEndAddress();
352 if (fnd && dist == 1)
353 break;
355 if (cpos < lpos)
356 cpos = lpos;
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))
364 if (fnd)
365 break;
366 cpos -= dist;
368 else
370 if (dist == 1)
371 fnd = true;
372 cpos += dist;
375 while (true);
377 trk = FindTrack(ltrk);
378 if (trk != 0)
380 idx = const_cast<IOptItem*>(trk)->addChild();
381 idx->setStartAddress(lpos);
382 idx->setEndAddress(cpos-1);
383 idx->setItemNumber(lidx);
386 lpos = cpos;
388 while (lpos != GetContents()->getEndAddress());
390 delete subq;
391 return 0;
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);
402 IOptItem *indx;
403 uint8 ctn, cin, ltn, lin;
404 int32 spos, cpos, epos, dlta;
405 bool done;
407 // don't read subchannel data for blanks. it won't work.
408 if (trak->isBlank())
409 continue;
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))
426 break;
428 // we always check at most the last sector.
429 epos = trak->getEndAddress();
430 cpos = epos;
431 dlta = cpos - spos;
432 done = false;
434 // typical loop inside to find further indices.
435 while (ODE_OK == getSubChannelInfo(cpos, ctn, cin))
437 if (dlta == 1)
438 done = true;
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))
444 break;
445 if ((cin == lin) && (done))
446 break;
447 else if (cin == lin)
448 cpos += dlta;
449 else
450 cpos -= dlta;
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(),
457 lin,
458 spos,
459 cpos);
460 indx = const_cast<IOptItem*>(trak)->addChild();
461 indx->setStartAddress(spos);
462 indx->setEndAddress(cpos);
463 indx->setItemNumber(lin);
464 spos = cpos + 1;
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__);
476 continue;
481 return 0;
484 int Disc_CD_ROM::CheckItemData(const IOptItem*)
486 _D(Lvl_Info, "Inserted disc is not writable");
487 return ODE_DiscFull;
490 int Disc_CD_ROM::RandomRead(const IOptItem *i, int32 first, int32 count, void* buff)
492 uint16 flags = 0;
494 if (0 == i)
496 i = GetContents();
499 if (!buff)
501 _D(Lvl_Warning, "No memory passed.");
502 return ODE_NoMemory;
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())
522 case Item_Disc:
523 case Item_Session:
524 flags = cmd_ReadCD::Flg_Sync | cmd_ReadCD::Flg_12BHeader | cmd_ReadCD::Flg_ECC;
525 default:
526 flags |= cmd_ReadCD::Flg_UserData;
527 break;
531 int err = pReadCD->readCD(first, count, i->getSectorSize(), buff, flags);
532 return err;
535 int Disc_CD_ROM::EndTrackWrite(const IOptItem*)
537 return ODE_IllegalCommand;
540 void Disc_CD_ROM::FillDiscSpeed(DiscSpeed &spd)
542 spd.f = 0;
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;
552 uint32 id1 = 0;
553 uint32 id2 = 0;
554 uint32 dbid= 0;
556 freedbid = 0;
558 toc = rtc.GetTOC(true);
559 if (0 == toc)
560 return 0;
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());
573 freedbid = dbid;
575 return dbid;
578 int Disc_CD_ROM::sumDigits(int32 val)
580 int32 res = 0;
582 while (val > 0)
584 res += (val % 10);
585 val /= 10;
588 return res;