File indexing completed on 2024-05-12 04:51:02
0001 /* 0002 SPDX-FileCopyrightText: 2003-2008 Sebastian Trueg <trueg@k3b.org> 0003 SPDX-FileCopyrightText: 2009 Gustavo Pichorim Boiko <gustavo.boiko@kdemail.net> 0004 SPDX-FileCopyrightText: 2010 Michal Malek <michalm@jabster.pl> 0005 SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 0011 #include "k3baudiotrack.h" 0012 #include "k3baudiodoc.h" 0013 #include "k3baudiodatasource.h" 0014 #include "k3baudiotrackreader.h" 0015 0016 #include "k3baudiodecoder.h" 0017 #include "k3bcore.h" 0018 #include "k3bcdtextvalidator.h" 0019 0020 #include <QDebug> 0021 #include <QString> 0022 0023 0024 0025 class K3b::AudioTrack::Private 0026 { 0027 public: 0028 Private( AudioDoc* p = 0 ) 0029 : 0030 parent(p), 0031 copy(false), 0032 preEmp(false), 0033 index0Offset(150), 0034 prev(0), 0035 next(0), 0036 firstSource(0), 0037 currentlyDeleting(false) { 0038 cdTextValidator = new K3b::CdTextValidator(); 0039 } 0040 0041 ~Private() { 0042 delete cdTextValidator; 0043 } 0044 0045 AudioDoc* parent; 0046 0047 /** copy protection */ 0048 bool copy; 0049 bool preEmp; 0050 0051 Msf index0Offset; 0052 0053 Device::TrackCdText cdText; 0054 0055 // list 0056 AudioTrack* prev; 0057 AudioTrack* next; 0058 0059 AudioDataSource* firstSource; 0060 0061 bool currentlyDeleting; 0062 0063 K3b::CdTextValidator* cdTextValidator; 0064 }; 0065 0066 0067 K3b::AudioTrack::AudioTrack() 0068 : QObject(), 0069 d( new Private ) 0070 { 0071 } 0072 0073 0074 K3b::AudioTrack::AudioTrack( K3b::AudioDoc* parent ) 0075 : QObject(), 0076 d( new Private( parent ) ) 0077 { 0078 } 0079 0080 0081 K3b::AudioTrack::~AudioTrack() 0082 { 0083 qDebug() << this; 0084 0085 d->currentlyDeleting = true; 0086 0087 // fix the list 0088 take(); 0089 0090 qDebug() << "deleting sources."; 0091 0092 // delete all sources 0093 while( d->firstSource ) 0094 delete d->firstSource->take(); 0095 0096 qDebug() << "finished"; 0097 0098 delete d; 0099 } 0100 0101 0102 K3b::AudioDoc* K3b::AudioTrack::doc() const 0103 { 0104 return d->parent; 0105 } 0106 0107 0108 void K3b::AudioTrack::emitChanged() 0109 { 0110 emit changed(); 0111 0112 if( d->parent && !d->currentlyDeleting ) 0113 d->parent->slotTrackChanged( this ); 0114 } 0115 0116 0117 void K3b::AudioTrack::setArtist( const QString& a ) 0118 { 0119 setPerformer( a ); 0120 } 0121 0122 0123 void K3b::AudioTrack::setPerformer( const QString& a ) 0124 { 0125 if( performer() != a ) { 0126 QString s( a ); 0127 d->cdTextValidator->fixup( s ); 0128 d->cdText.setPerformer(s); 0129 emitChanged(); 0130 } 0131 } 0132 0133 0134 void K3b::AudioTrack::setTitle( const QString& t ) 0135 { 0136 if( title() != t ) { 0137 QString s( t ); 0138 d->cdTextValidator->fixup( s ); 0139 d->cdText.setTitle(s); 0140 emitChanged(); 0141 } 0142 } 0143 0144 0145 void K3b::AudioTrack::setArranger( const QString& t ) 0146 { 0147 if( arranger() != t ) { 0148 QString s( t ); 0149 d->cdTextValidator->fixup( s ); 0150 d->cdText.setArranger(s); 0151 emitChanged(); 0152 } 0153 } 0154 0155 0156 void K3b::AudioTrack::setSongwriter( const QString& t ) 0157 { 0158 if( songwriter() != t ) { 0159 QString s( t ); 0160 d->cdTextValidator->fixup( s ); 0161 d->cdText.setSongwriter(s); 0162 emitChanged(); 0163 } 0164 } 0165 0166 0167 void K3b::AudioTrack::setComposer( const QString& t ) 0168 { 0169 if( composer() != t ) { 0170 QString s( t ); 0171 d->cdTextValidator->fixup( s ); 0172 d->cdText.setComposer(s); 0173 emitChanged(); 0174 } 0175 } 0176 0177 0178 void K3b::AudioTrack::setIsrc( const QString& t ) 0179 { 0180 if( isrc() != t ) { 0181 d->cdText.setIsrc(t); 0182 emitChanged(); 0183 } 0184 } 0185 0186 0187 void K3b::AudioTrack::setCdTextMessage( const QString& t ) 0188 { 0189 if( cdTextMessage() != t ) { 0190 QString s( t ); 0191 d->cdTextValidator->fixup( s ); 0192 d->cdText.setMessage(s); 0193 emitChanged(); 0194 } 0195 } 0196 0197 0198 void K3b::AudioTrack::setCdText( const K3b::Device::TrackCdText& cdtext ) 0199 { 0200 d->cdText = cdtext; 0201 emitChanged(); 0202 } 0203 0204 0205 void K3b::AudioTrack::setPreEmp( bool b ) 0206 { 0207 if( d->preEmp != b ) { 0208 d->preEmp = b; 0209 emitChanged(); 0210 } 0211 } 0212 0213 0214 void K3b::AudioTrack::setCopyProtection( bool b ) 0215 { 0216 if( d->copy != b ) { 0217 d->copy = b; 0218 emitChanged(); 0219 } 0220 } 0221 0222 0223 K3b::AudioDataSource* K3b::AudioTrack::firstSource() const 0224 { 0225 return d->firstSource; 0226 } 0227 0228 0229 K3b::AudioDataSource* K3b::AudioTrack::lastSource() const 0230 { 0231 K3b::AudioDataSource* s = d->firstSource; 0232 while( s && s->next() ) 0233 s = s->next(); 0234 return s; 0235 } 0236 0237 0238 bool K3b::AudioTrack::inList() const 0239 { 0240 if( doc() ) 0241 return ( doc()->firstTrack() == this || d->prev != 0 ); 0242 else 0243 return false; 0244 } 0245 0246 0247 K3b::Msf K3b::AudioTrack::length() const 0248 { 0249 K3b::Msf length; 0250 K3b::AudioDataSource* source = d->firstSource; 0251 while( source ) { 0252 length += source->length(); 0253 source = source->next(); 0254 } 0255 return length; 0256 } 0257 0258 0259 KIO::filesize_t K3b::AudioTrack::size() const 0260 { 0261 return length().audioBytes(); 0262 } 0263 0264 QString K3b::AudioTrack::artist() const 0265 { 0266 return d->cdText.performer(); 0267 } 0268 0269 0270 QString K3b::AudioTrack::performer() const 0271 { 0272 return d->cdText.performer(); 0273 } 0274 0275 0276 QString K3b::AudioTrack::title() const 0277 { 0278 return d->cdText.title(); 0279 } 0280 0281 0282 QString K3b::AudioTrack::arranger() const 0283 { 0284 return d->cdText.arranger(); 0285 } 0286 0287 0288 QString K3b::AudioTrack::songwriter() const 0289 { 0290 return d->cdText.songwriter(); 0291 } 0292 0293 0294 QString K3b::AudioTrack::composer() const 0295 { 0296 return d->cdText.composer(); 0297 } 0298 0299 0300 QString K3b::AudioTrack::isrc() const 0301 { 0302 return d->cdText.isrc(); 0303 } 0304 0305 0306 QString K3b::AudioTrack::cdTextMessage() const 0307 { 0308 return d->cdText.message(); 0309 } 0310 0311 0312 K3b::Device::TrackCdText K3b::AudioTrack::cdText() const 0313 { 0314 return d->cdText; 0315 } 0316 0317 0318 bool K3b::AudioTrack::copyProtection() const 0319 { 0320 return d->copy; 0321 } 0322 0323 0324 bool K3b::AudioTrack::preEmp() const 0325 { 0326 return d->preEmp; 0327 } 0328 0329 0330 unsigned int K3b::AudioTrack::trackNumber() const 0331 { 0332 if( d->prev ) 0333 return d->prev->trackNumber() + 1; 0334 else 0335 return 1; 0336 } 0337 0338 0339 K3b::Msf K3b::AudioTrack::index0() const 0340 { 0341 // we save the index0Offset as length of the resulting pregap 0342 // this way the length of the track does not need to be ready 0343 // when creating the track. 0344 return length() - d->index0Offset; 0345 } 0346 0347 0348 K3b::Msf K3b::AudioTrack::postGap() const 0349 { 0350 if( next() ) 0351 return d->index0Offset; 0352 else 0353 return 0; 0354 } 0355 0356 0357 void K3b::AudioTrack::setIndex0( const K3b::Msf& msf ) 0358 { 0359 if( msf == 0 ) 0360 d->index0Offset = 0; 0361 else 0362 d->index0Offset = length() - msf; 0363 } 0364 0365 0366 K3b::AudioTrack* K3b::AudioTrack::take() 0367 { 0368 if( inList() ) { 0369 const int position = trackNumber() - 1; 0370 if ( doc() ) 0371 emit doc()->trackAboutToBeRemoved( position ); 0372 0373 if( !d->prev ) 0374 doc()->setFirstTrack( d->next ); 0375 if( !d->next ) 0376 doc()->setLastTrack( d->prev ); 0377 0378 if( d->prev ) 0379 d->prev->d->next = d->next; 0380 if( d->next ) 0381 d->next->d->prev = d->prev; 0382 0383 d->prev = d->next = 0; 0384 0385 // remove from doc 0386 if( doc() ) 0387 doc()->slotTrackRemoved( position ); 0388 0389 d->parent = 0; 0390 } 0391 0392 return this; 0393 } 0394 0395 0396 void K3b::AudioTrack::moveAfter( K3b::AudioTrack* track ) 0397 { 0398 qDebug() << "(K3b::AudioTrack::moveAfter( " << track << " )"; 0399 if( !track ) { 0400 if( !doc() ) { 0401 qDebug() << "(K3b::AudioTrack::moveAfter) no parent set"; 0402 return; 0403 } 0404 0405 // make sure we do not mess up the list 0406 if( doc()->lastTrack() ) 0407 moveAfter( doc()->lastTrack() ); 0408 else { 0409 emit doc()->trackAboutToBeAdded( 0 ); 0410 doc()->setFirstTrack( take() ); 0411 doc()->setLastTrack( this ); 0412 emit doc()->trackAdded( 0 ); 0413 } 0414 } 0415 else if( track == this ) { 0416 qDebug() << "(K3b::AudioTrack::moveAfter) trying to move this after this."; 0417 return; 0418 } 0419 else { 0420 // remove this from the list 0421 take(); 0422 0423 emit track->doc()->trackAboutToBeAdded( track->trackNumber()-1 ); 0424 0425 // set the new parent doc 0426 d->parent = track->doc(); 0427 0428 K3b::AudioTrack* oldNext = track->d->next; 0429 0430 // set track as prev 0431 track->d->next = this; 0432 d->prev = track; 0433 0434 // set oldNext as next 0435 if( oldNext ) 0436 oldNext->d->prev = this; 0437 d->next = oldNext; 0438 0439 if( !d->prev ) 0440 doc()->setFirstTrack( this ); 0441 if( !d->next ) 0442 doc()->setLastTrack( this ); 0443 0444 emit doc()->trackAdded( track->trackNumber()-1 ); 0445 } 0446 0447 emitChanged(); 0448 } 0449 0450 0451 void K3b::AudioTrack::moveAhead( K3b::AudioTrack* track ) 0452 { 0453 if( !track ) { 0454 if( !doc() ) { 0455 qDebug() << "(K3b::AudioTrack::moveAfter) no parent set"; 0456 return; 0457 } 0458 0459 // make sure we do not mess up the list 0460 if( doc()->firstTrack() ) 0461 moveAhead( doc()->firstTrack() ); 0462 else { 0463 emit doc()->trackAboutToBeAdded( 0 ); 0464 doc()->setFirstTrack( take() ); 0465 doc()->setLastTrack( this ); 0466 emit doc()->trackAdded( 0 ); 0467 } 0468 } 0469 else if( track == this ) { 0470 qDebug() << "(K3b::AudioTrack::moveAhead) trying to move this ahead of this."; 0471 return; 0472 } 0473 else { 0474 // remove this from the list 0475 take(); 0476 0477 emit track->doc()->trackAboutToBeAdded( track->trackNumber()-1 ); 0478 0479 // set the new parent doc 0480 d->parent = track->doc(); 0481 0482 K3b::AudioTrack* oldPrev = track->d->prev; 0483 0484 // set track as next 0485 d->next = track; 0486 track->d->prev = this; 0487 0488 // set oldPrev as prev 0489 d->prev = oldPrev; 0490 if( oldPrev ) 0491 oldPrev->d->next = this; 0492 0493 if( !d->prev ) 0494 doc()->setFirstTrack( this ); 0495 if( !d->next ) 0496 doc()->setLastTrack( this ); 0497 0498 emit doc()->trackAdded( track->trackNumber()-1 ); 0499 } 0500 0501 emitChanged(); 0502 } 0503 0504 0505 void K3b::AudioTrack::merge( K3b::AudioTrack* trackToMerge, K3b::AudioDataSource* sourceAfter ) 0506 { 0507 qDebug() << "(K3b::AudioTrack::merge) " << trackToMerge << " into " << this; 0508 if( this == trackToMerge ) { 0509 qDebug() << "(K3b::AudioTrack::merge) trying to merge this with this."; 0510 return; 0511 } 0512 0513 // remove the track to merge to make sure it does not get deleted by the doc too early 0514 trackToMerge->take(); 0515 0516 // in case we prepend all of trackToMerge's sources 0517 if( !sourceAfter ) { 0518 qDebug() << "(K3b::AudioTrack::merge) merging " << trackToMerge->firstSource(); 0519 if( d->firstSource ) { 0520 trackToMerge->firstSource()->moveAhead( d->firstSource ); 0521 } 0522 else { 0523 addSource( trackToMerge->firstSource()->take() ); 0524 } 0525 sourceAfter = d->firstSource; 0526 } 0527 0528 qDebug() << "(K3b::AudioTrack::merge) now merge the other sources."; 0529 // now merge all sources into this track 0530 while( trackToMerge->firstSource() ) { 0531 K3b::AudioDataSource* s = trackToMerge->firstSource(); 0532 qDebug() << "(K3b::AudioTrack::merge) merging source " << s << " from track " << s->track() << " into track " 0533 << this << " after source " << sourceAfter << Qt::endl; 0534 s->moveAfter( sourceAfter ); 0535 sourceAfter = s; 0536 } 0537 0538 // TODO: should we also merge the indices? 0539 0540 // now we can safely delete the track we merged 0541 delete trackToMerge; 0542 0543 qDebug() << "(K3b::AudioTrack::merge) finished"; 0544 0545 emitChanged(); 0546 } 0547 0548 0549 K3b::AudioTrack* K3b::AudioTrack::prev() const 0550 { 0551 return d->prev; 0552 } 0553 0554 0555 K3b::AudioTrack* K3b::AudioTrack::next() const 0556 { 0557 return d->next; 0558 } 0559 0560 0561 void K3b::AudioTrack::setFirstSource( K3b::AudioDataSource* source ) 0562 { 0563 d->firstSource = source; 0564 while( source ) { 0565 source->m_track = this; 0566 source = source->next(); 0567 } 0568 0569 emitChanged(); 0570 } 0571 0572 0573 void K3b::AudioTrack::addSource( K3b::AudioDataSource* source ) 0574 { 0575 if( !source ) 0576 return; 0577 0578 K3b::AudioDataSource* s = d->firstSource; 0579 while( s && s->next() ) 0580 s = s->next(); 0581 if( s ) 0582 source->moveAfter( s ); 0583 else 0584 setFirstSource( source->take() ); 0585 } 0586 0587 0588 void K3b::AudioTrack::sourceChanged( K3b::AudioDataSource* ) 0589 { 0590 if( d->currentlyDeleting ) 0591 return; 0592 0593 // TODO: update indices 0594 0595 if( d->index0Offset > length() ) 0596 d->index0Offset = length()-1; 0597 0598 emitChanged(); 0599 } 0600 0601 0602 int K3b::AudioTrack::numberSources() const 0603 { 0604 K3b::AudioDataSource* source = d->firstSource; 0605 int i = 0; 0606 while( source ) { 0607 source = source->next(); 0608 ++i; 0609 } 0610 return i; 0611 } 0612 0613 0614 K3b::AudioTrack* K3b::AudioTrack::copy() const 0615 { 0616 K3b::AudioTrack* track = new K3b::AudioTrack(); 0617 0618 track->d->copy = d->copy; 0619 track->d->preEmp = d->preEmp; 0620 track->d->index0Offset = d->index0Offset; 0621 track->d->cdText = d->cdText; 0622 K3b::AudioDataSource* source = d->firstSource; 0623 while( source ) { 0624 track->addSource( source->copy() ); 0625 source = source->next(); 0626 } 0627 0628 return track; 0629 } 0630 0631 0632 K3b::AudioTrack* K3b::AudioTrack::split( const K3b::Msf& pos ) 0633 { 0634 if( pos < length() ) { 0635 // search the source 0636 // pos will be the first sector of the new track 0637 K3b::Msf currentPos; 0638 K3b::AudioDataSource* source = firstSource(); 0639 while( source && currentPos + source->length() <= pos ) { 0640 currentPos += source->length(); 0641 source = source->next(); 0642 } 0643 0644 K3b::AudioDataSource* splitSource = 0; 0645 if( currentPos > 0 && currentPos == pos ) { 0646 // no need to split a source 0647 splitSource = source; 0648 } 0649 else { 0650 if (source) 0651 splitSource = source->split( pos - currentPos ); 0652 } 0653 0654 // the new track should include all sources from splitSource and below 0655 K3b::AudioTrack* splitTrack = new K3b::AudioTrack(); 0656 splitTrack->d->cdText = d->cdText; 0657 source = splitSource; 0658 while( source ) { 0659 K3b::AudioDataSource* addSource = source; 0660 source = source->next(); 0661 splitTrack->addSource( addSource ); 0662 } 0663 0664 qDebug() << "(K3b::AudioTrack) moving track " << splitTrack << " after this (" << this << ") with parent " << doc(); 0665 splitTrack->moveAfter( this ); 0666 0667 return splitTrack; 0668 } 0669 else 0670 return 0; 0671 } 0672 0673 0674 QIODevice* K3b::AudioTrack::createReader( QObject* parent ) 0675 { 0676 return new AudioTrackReader( *this, parent ); 0677 } 0678 0679 0680 K3b::Device::Track K3b::AudioTrack::toCdTrack() const 0681 { 0682 if( !inList() ) 0683 return K3b::Device::Track(); 0684 0685 K3b::Msf firstSector; 0686 K3b::AudioTrack* track = doc()->firstTrack(); 0687 while( track != this ) { 0688 firstSector += track->length(); 0689 track = track->next(); 0690 } 0691 0692 K3b::Device::Track cdTrack( firstSector, 0693 firstSector + length() - 1, 0694 K3b::Device::Track::TYPE_AUDIO ); 0695 0696 // FIXME: auch im audiotrack copy permitted 0697 cdTrack.setCopyPermitted( !copyProtection() ); 0698 cdTrack.setPreEmphasis( preEmp() ); 0699 0700 // FIXME: add indices != 0 0701 0702 // no index 0 for the last track. Or should we allow this??? 0703 if( doc()->lastTrack() != this ) 0704 cdTrack.setIndex0( index0() ); 0705 0706 // FIXME: convert to QCString 0707 // cdTrack.setIsrc( isrc() ); 0708 0709 return cdTrack; 0710 } 0711 0712 0713 void K3b::AudioTrack::debug() 0714 { 0715 qDebug() << "Track " << this << Qt::endl 0716 << " Prev: " << d->prev << Qt::endl 0717 << " Next: " << d->next << Qt::endl 0718 << " Sources:" << Qt::endl; 0719 K3b::AudioDataSource* s = d->firstSource; 0720 while( s ) { 0721 qDebug() << " " << s << " - Prev: " << s->prev() << " Next: " << s->next(); 0722 s = s->next(); 0723 } 0724 } 0725 0726 0727 K3b::AudioDataSource* K3b::AudioTrack::getSource( int index ) const 0728 { 0729 int i = 0; 0730 K3b::AudioDataSource* source = firstSource(); 0731 while ( source && i < index ) { 0732 source = source->next(); 0733 ++i; 0734 } 0735 return source; 0736 } 0737 0738 0739 void K3b::AudioTrack::emitSourceAboutToBeRemoved( AudioDataSource* source ) 0740 { 0741 emit sourceAboutToBeRemoved( source->sourceIndex() ); 0742 0743 if ( doc() ) { 0744 emit doc()->sourceAboutToBeRemoved( this, source->sourceIndex() ); 0745 } 0746 } 0747 0748 0749 void K3b::AudioTrack::emitSourceRemoved( K3b::AudioDataSource* source ) 0750 { 0751 if ( doc() ) { 0752 // set the first source by hand (without using setFirstSource() ) 0753 // just to avoid the model to read invalid firstSources 0754 if ( !source->prev() ) 0755 d->firstSource = source->next(); 0756 0757 emit doc()->sourceRemoved( this, source->sourceIndex() ); 0758 } 0759 0760 emit sourceRemoved( source->sourceIndex() ); 0761 0762 // and now call the setFirstSource() to make sure the proper signals 0763 // are emitted 0764 if ( !source->prev() ) 0765 setFirstSource( source->next() ); 0766 } 0767 0768 0769 void K3b::AudioTrack::emitSourceAboutToBeAdded( int position ) 0770 { 0771 emit sourceAboutToBeAdded( position ); 0772 0773 if ( doc() ) { 0774 emit doc()->sourceAboutToBeAdded( this, position ); 0775 } 0776 } 0777 0778 0779 void K3b::AudioTrack::emitSourceAdded( AudioDataSource* source ) 0780 { 0781 if ( doc() ) { 0782 emit doc()->sourceAdded( this, source->sourceIndex() ); 0783 doc()->slotTrackChanged( this ); 0784 } else { 0785 emit sourceAdded( source->sourceIndex() ); 0786 } 0787 } 0788 0789 0790 void K3b::AudioTrack::setIndex0Offset( const Msf& index0Offset ) 0791 { 0792 d->index0Offset = index0Offset; 0793 } 0794 0795 0796 void K3b::AudioTrack::setParent( K3b::AudioDoc* parent ) 0797 { 0798 d->parent = parent; 0799 } 0800 0801 #include "moc_k3baudiotrack.cpp"