diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 9f93a4c23..ddc7d7356 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -1674,8 +1674,8 @@ void MainWindow::AddStreamAccepted() { void MainWindow::OpenRipCD() { if (!rip_cd_) { - rip_cd_.reset(new RipCD); - } + rip_cd_.reset(new RipCD); + } rip_cd_->show(); } diff --git a/src/ui/ripcd.cpp b/src/ui/ripcd.cpp index 91637dc7f..e81174805 100644 --- a/src/ui/ripcd.cpp +++ b/src/ui/ripcd.cpp @@ -29,11 +29,7 @@ #include #include #include -#include #include -//#include -#include -#include #include #include #include @@ -48,20 +44,37 @@ # undef AddJob #endif -static bool ComparePresetsByName(const TranscoderPreset& left, +namespace { + bool ComparePresetsByName(const TranscoderPreset& left, const TranscoderPreset& right) { - return left.name_ < right.name_; -} + return left.name_ < right.name_; + } + const char kWavHeaderRiffMarker[] = "RIFF"; + const char kWavFileTypeFormatChunk[] = "WAVEfmt "; + const char kWavDataString[] = "data"; + + const int kCheckboxColumn = 0; + const int kTrackNumberColumn = 1; + const int kTrackTitleColumn = 2; + +} const char* RipCD::kSettingsGroup = "Transcoder"; const int RipCD::kProgressInterval = 500; const int RipCD::kMaxDestinationItems = 10; RipCD::RipCD(QWidget* parent) : - QDialog(parent), transcoder_(new Transcoder(this)), queued_(0), finished_success_( - 0), finished_failed_(0), ui_(new Ui_RipCD()), checkboxes_( - QList()), generated_files_(QList()), tracks_to_rip_( - QList()), track_names_(QList()) { + QDialog(parent), + transcoder_(new Transcoder(this)), + queued_(0), + finished_success_(0), + finished_failed_(0), + ui_(new Ui_RipCD()), + checkboxes_(QList()), + generated_files_(QList()), + tracks_to_rip_(QList()), + track_names_(QList()) +{ // Init ui_->setupUi(this); cancel_button_ = ui_->button_box->button(QDialogButtonBox::Cancel); @@ -74,33 +87,32 @@ RipCD::RipCD(QWidget* parent) : connect(transcoder_, SIGNAL(JobOutputName(QString)), SLOT(AppendOutput(QString))); connect(this, SIGNAL(RippingComplete()), SLOT(ThreadedTranscoding())); - connect(this, SIGNAL(signalUpdateProgress()), SLOT(UpdateProgress())); + connect(this, SIGNAL(SignalUpdateProgress()), SLOT(UpdateProgress())); connect(ui_->options, SIGNAL(clicked()), SLOT(Options())); connect(ui_->select, SIGNAL(clicked()), SLOT(AddDestination())); setWindowTitle(tr("Rip CD")); - p_cdio_ = cdio_open(NULL, DRIVER_UNKNOWN); - i_tracks = cdio_get_num_tracks(p_cdio_); + cdio_ = cdio_open(NULL, DRIVER_UNKNOWN); + i_tracks = cdio_get_num_tracks(cdio_); ui_->tableWidget->setRowCount(i_tracks); + for (int i = 1; i <= i_tracks; i++) { - QCheckBox *_t = new QCheckBox(tr(""), ui_->tableWidget); - _t->click(); - checkboxes_.append(_t); - ui_->tableWidget->setCellWidget(i - 1, 0, _t); - ui_->tableWidget->setCellWidget(i - 1, 1, new QLabel(QString::number(i))); - QString _str_track; - _str_track = "Track %1"; - QLineEdit *_ql = new QLineEdit(_str_track.arg(QString::number(i)), - ui_->tableWidget); - track_names_.append(_ql); - ui_->tableWidget->setCellWidget(i - 1, 2, _ql); + QCheckBox *checkbox_i = new QCheckBox(tr(""), ui_->tableWidget); + checkbox_i->click(); + checkboxes_.append(checkbox_i); + ui_->tableWidget->setCellWidget(i - 1, kCheckboxColumn, checkbox_i); + ui_->tableWidget->setCellWidget(i - 1, kTrackNumberColumn, new QLabel(QString::number(i))); + QString track_title = QString("Track %1").arg(i); + QLineEdit *line_edit_track_title_i = new QLineEdit(track_title,ui_->tableWidget); + track_names_.append(line_edit_track_title_i); + ui_->tableWidget->setCellWidget(i - 1, kTrackTitleColumn, line_edit_track_title_i); } // Get presets - QList < TranscoderPreset > presets = Transcoder::GetAllPresets(); + QList presets = Transcoder::GetAllPresets(); qSort(presets.begin(), presets.end(), ComparePresetsByName); - foreach(const TranscoderPreset& preset, presets) { + for(const TranscoderPreset& preset : presets) { ui_->format->addItem( QString("%1 (.%2)").arg(preset.name_, preset.extension_), QVariant::fromValue(preset)); @@ -124,10 +136,35 @@ RipCD::RipCD(QWidget* parent) : ui_->progress_bar->setMaximum(100); } -void RipCD::WriteWAVHeader(FILE *stream, int32_t i_bytecount) { - fwrite("RIFF", sizeof(char), 4, stream); +/* + * WAV Header documentation + * as taken from: + * http://www.topherlee.com/software/pcm-tut-wavformat.html + * Pos Value Description + * 0-3 | "RIFF" | Marks the file as a riff file. + * | Characters are each 1 byte long. + * 4-7 | File size (integer) | Size of the overall file - 8 bytes, + * | in bytes (32-bit integer). + * 8-11 | "WAVE" | File Type Header. For our purposes, + * | it always equals "WAVE". + * 13-16 | "fmt " | Format chunk marker. Includes trailing null. + * 17-20 | 16 | Length of format data as listed above + * 21-22 | 1 | Type of format (1 is PCM) - 2 byte integer + * 23-24 | 2 | Number of Channels - 2 byte integer + * 25-28 | 44100 | Sample Rate - 32 byte integer. Common values + * | are 44100 (CD), 48000 (DAT). + * | Sample Rate = Number of Samples per second, or Hertz. + * 29-32 | 176400 | (Sample Rate * BitsPerSample * Channels) / 8. + * 33-34 | 4 | (BitsPerSample * Channels) / 8.1 - 8 bit mono2 - 8 bit stereo/16 bit mono4 - 16 bit stereo + * 35-36 | 16 | Bits per sample + * 37-40 | "data" | "data" chunk header. + * | Marks the beginning of the data section. + * 41-44 | File size (data) | Size of the data section. + */ +void RipCD::WriteWAVHeader(QFile *stream, int32_t i_bytecount) { + stream->write(kWavHeaderRiffMarker); /* 0-3 */ PutNum(i_bytecount + 44 - 8, stream, 4); /* 4-7 */ - fwrite("WAVEfmt ", sizeof(char), 8, stream); /* 8-15 */ + stream->write(kWavFileTypeFormatChunk); /* 8-15 */ PutNum(16, stream, 4); /* 16-19 */ PutNum(1, stream, 2); /* 20-21 */ PutNum(2, stream, 2); /* 22-23 */ @@ -135,27 +172,27 @@ void RipCD::WriteWAVHeader(FILE *stream, int32_t i_bytecount) { PutNum(44100 * 2 * 2, stream, 4); /* 28-31 */ PutNum(4, stream, 2); /* 32-33 */ PutNum(16, stream, 2); /* 34-35 */ - fwrite("data", sizeof(char), 4, stream); /* 36-39 */ + stream->write(kWavDataString); /* 36-39 */ PutNum(i_bytecount, stream, 4); /* 40-43 */ } -void RipCD::PutNum(int64_t num, FILE *stream, int bytes) { +void RipCD::PutNum(int64_t num, QFile *stream, int bytes) { unsigned int i; - unsigned char c; + unsigned char c; - for (i = 0; bytes--; i++) { - c = (num >> (i << 3)) & 0xff; - if (fwrite(&c, sizeof(char), 1, stream) == -1) { - perror("Could not write to output."); - exit(1); + for (i = 0; bytes--; i++) { + c = (num >> (i << 3)) & 0xff; + if (stream->write(reinterpret_cast(&c), sizeof(c)) == -1) { + perror("Could not write to output."); + exit(1); + } } - } } int RipCD::NumTracksToRip() { int k = 0; for (int i = 0; i < checkboxes_.length(); i++) { - if (checkboxes_.value(i)->isChecked() == true) { + if (checkboxes_.value(i)->isChecked()) { k++; } } @@ -169,43 +206,41 @@ void RipCD::ThreadClickedRipButton() { finished_failed_ = 0; ui_->progress_bar->setMaximum(NumTracksToRip() * 2 * 100); + // Set up progress bar emit(SignalUpdateProgress()); - // Set up the progressbar for (int i = 1; i <= i_tracks; i++) { - if (checkboxes_.value(i - 1)->isChecked() == false) { + if (!checkboxes_.value(i - 1)->isChecked()) { continue; } tracks_to_rip_.append(i); - lsn_t i_first_lsn = cdio_get_track_lsn(p_cdio_, i); - lsn_t i_last_lsn = cdio_get_track_last_lsn(p_cdio_, i); - - lsn_t i_cursor; - int16_t *p_readbuf = reinterpret_cast - (calloc(CDIO_CD_FRAMESIZE_RAW, 1)); QString filename = source_directory + ParseFileFormatString(ui_->format_filename->text(), i) + ".wav"; - FILE *fp = fopen(filename.toUtf8().constData(), "w"); - WriteWAVHeader(fp, - (i_last_lsn - i_first_lsn + 1) * CDIO_CD_FRAMESIZE_RAW); + QFile* destination_file = new QFile(filename); + destination_file->open(QIODevice::WriteOnly); - for (i_cursor = i_first_lsn; i_cursor <= i_last_lsn; i_cursor++) { - cdio_read_audio_sector(p_cdio_, p_readbuf, i_cursor); - if (!p_readbuf) { + lsn_t i_first_lsn = cdio_get_track_lsn(cdio_, i); + lsn_t i_last_lsn = cdio_get_track_last_lsn(cdio_, i); + WriteWAVHeader(destination_file, + (i_last_lsn - i_first_lsn + 1) * CDIO_CD_FRAMESIZE_RAW); + + QByteArray *buffered_input_bytes = new QByteArray(); + buffered_input_bytes->resize(CDIO_CD_FRAMESIZE_RAW); + for (lsn_t i_cursor = i_first_lsn; i_cursor <= i_last_lsn; i_cursor++) { + cdio_read_audio_sector(cdio_, buffered_input_bytes->data(), i_cursor); + if (!buffered_input_bytes->data()) { qDebug() << "Read error. Stopping."; break; } else { - fwrite(p_readbuf, 1, CDIO_CD_FRAMESIZE_RAW, fp); + destination_file->write(buffered_input_bytes->data(), CDIO_CD_FRAMESIZE_RAW); } } finished_success_++; emit(SignalUpdateProgress()); - fclose(fp); - free(p_readbuf); - p_readbuf = NULL; - + destination_file->close(); + delete buffered_input_bytes; TranscoderPreset preset = ui_->format->itemData(ui_->format->currentIndex()) .value(); @@ -236,15 +271,15 @@ QString RipCD::GetOutputFileName(const QString& input, } QString RipCD::ParseFileFormatString(const QString& file_format, - int trackNo) const { + int track_no) const { QString to_return = file_format; to_return.replace(QString("%artist%"), ui_->artistLineEdit->text()); to_return.replace(QString("%album%"), ui_->albumLineEdit->text()); to_return.replace(QString("%genre%"), ui_->genreLineEdit->text()); to_return.replace(QString("%year%"), ui_->yearLineEdit->text()); - to_return.replace(QString("%tracknum%"), QString::number(trackNo)); + to_return.replace(QString("%tracknum%"), QString::number(track_no)); to_return.replace(QString("%track%"), - track_names_.value(trackNo - 1)->text()); + track_names_.value(track_no - 1)->text()); return to_return; } @@ -282,8 +317,7 @@ void RipCD::AllJobsComplete() { // having a little trouble on wav files, works fine on ogg-vorbis qSort(generated_files_); - int i; - for (i = 0; i < generated_files_.length(); i++) { + for (int i = 0; i < generated_files_.length(); i++) { TagLib::FileRef f(generated_files_.value(i).toUtf8().constData()); f.tag()->setTitle( @@ -303,7 +337,7 @@ void RipCD::AllJobsComplete() { tracks_to_rip_.clear(); } -void RipCD::AppendOutput(const QString &filename) { +void RipCD::AppendOutput(const QString& filename) { generated_files_.append(filename); } diff --git a/src/ui/ripcd.h b/src/ui/ripcd.h index 66ddd3a48..b1aa74f8d 100644 --- a/src/ui/ripcd.h +++ b/src/ui/ripcd.h @@ -35,18 +35,18 @@ class RipCD: public QDialog { public: explicit RipCD(QWidget* parent = 0); + + private: static const char* kSettingsGroup; static const int kProgressInterval; static const int kMaxDestinationItems; - - private: Transcoder* transcoder_; int queued_; int finished_success_; int finished_failed_; track_t i_tracks; Ui_RipCD* ui_; - CdIo_t *p_cdio_; + CdIo_t *cdio_; QList checkboxes_; QList generated_files_; QList tracks_to_rip_; @@ -54,14 +54,14 @@ class RipCD: public QDialog { QString last_add_dir_; QPushButton* cancel_button_; - void WriteWAVHeader(FILE *stream, int32_t i_bytecount); - void PutNum(int64_t num, FILE *stream, int bytes); + void WriteWAVHeader(QFile* stream, int32_t i_bytecount); + void PutNum(int64_t num, QFile* stream, int bytes); int NumTracksToRip(); void ThreadClickedRipButton(); QString TrimPath(const QString& path) const; QString GetOutputFileName(const QString& input, const TranscoderPreset& preset) const; - QString ParseFileFormatString(const QString& file_format, int trackNo) const; + QString ParseFileFormatString(const QString& file_format, int track_no) const; signals: void RippingComplete(); @@ -72,7 +72,7 @@ class RipCD: public QDialog { void ClickedRipButton(); void JobComplete(const QString& filename, bool success); void AllJobsComplete(); - void AppendOutput(const QString &filename); + void AppendOutput(const QString& filename); void Options(); void AddDestination(); void Cancel();