164 lines
5.2 KiB
C++
164 lines
5.2 KiB
C++
/*
|
|
* Cantata
|
|
*
|
|
* Copyright (c) 2011-2022 Craig Drummond <craig.p.drummond@gmail.com>
|
|
*
|
|
* ----
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
*/
|
|
|
|
#include "extractjob.h"
|
|
#include "device.h"
|
|
#include "support/utils.h"
|
|
#include "tags/tags.h"
|
|
#include "cdparanoia.h"
|
|
#include "gui/covers.h"
|
|
#include "mpd-interface/mpdconnection.h"
|
|
#include "gui/settings.h"
|
|
#include <QStringList>
|
|
#include <QProcess>
|
|
#include <QFile>
|
|
|
|
const int ExtractJob::constWavHeaderSize=44; // ffmpeg uses 46 byte header?
|
|
|
|
static void insertSize(unsigned char *data, qint32 size)
|
|
{
|
|
data[0]=(size&0x000000ff);
|
|
data[1]=(size&0x0000ff00)>>8;
|
|
data[2]=(size&0x00ff0000)>>16;
|
|
data[3]=(size&0xff000000)>>24;
|
|
}
|
|
|
|
void ExtractJob::writeWavHeader(QIODevice &dev, qint32 size)
|
|
{
|
|
unsigned char riffHeader[] = {
|
|
0x52, 0x49, 0x46, 0x46, // 0 "RIFF"
|
|
0x00, 0x00, 0x00, 0x00, // 4 wavSize
|
|
0x57, 0x41, 0x56, 0x45, // 8 "WAVE"
|
|
0x66, 0x6d, 0x74, 0x20, // 12 "fmt "
|
|
0x10, 0x00, 0x00, 0x00, // 16 Size of WAVE section chunk (ffmpeg has 12 here???)
|
|
0x01, 0x00, 0x02, 0x00, // 20 WAVE type format / Number of channels
|
|
0x44, 0xac, 0x00, 0x00, // 24 Samples per second
|
|
0x10, 0xb1, 0x02, 0x00, // 28 Bytes per second
|
|
0x04, 0x00, 0x10, 0x00, // 32 Block alignment / Bits per sample
|
|
0x64, 0x61, 0x74, 0x61, // 36 "data" (ffmpeg preceeds this with two 0 bytes)
|
|
0x00, 0x00, 0x00, 0x00 // 40 byteCount
|
|
};
|
|
|
|
if (0!=size) {
|
|
insertSize(&riffHeader[4], (size+constWavHeaderSize)-8);
|
|
insertSize(&riffHeader[40], size);
|
|
}
|
|
|
|
dev.write((char*)riffHeader, constWavHeaderSize);
|
|
}
|
|
|
|
ExtractJob::ExtractJob(const Encoders::Encoder &enc, int val, const QString &src, const QString &dest, const Song &s, const QString &cover)
|
|
: encoder(enc)
|
|
, value(val)
|
|
, srcFile(src)
|
|
, destFile(dest)
|
|
, song(s)
|
|
, coverFile(cover)
|
|
, copiedCover(false)
|
|
{
|
|
}
|
|
|
|
ExtractJob::~ExtractJob()
|
|
{
|
|
}
|
|
|
|
void ExtractJob::run()
|
|
{
|
|
if (stopRequested) {
|
|
emit result(Device::Cancelled);
|
|
} else {
|
|
QStringList encParams=encoder.params(value, encoder.transcoder ? "pipe:" : "-", destFile);
|
|
CdParanoia cdparanoia(srcFile, Settings::self()->paranoiaFull(), Settings::self()->paranoiaNeverSkip(), false, Settings::self()->paranoiaOffset());
|
|
|
|
if (!cdparanoia) {
|
|
emit result(Device::FailedToLockDevice);
|
|
return;
|
|
}
|
|
QProcess process;
|
|
QString cmd=encParams.takeFirst();
|
|
process.start(cmd, encParams, QIODevice::WriteOnly);
|
|
process.waitForStarted();
|
|
|
|
if (stopRequested) {
|
|
emit result(Device::Cancelled);
|
|
process.close();
|
|
return;
|
|
}
|
|
int firstSector = cdparanoia.firstSectorOfTrack(song.id);
|
|
int lastSector = cdparanoia.lastSectorOfTrack(song.id);
|
|
int total=lastSector-firstSector;
|
|
int count=0;
|
|
|
|
cdparanoia.seek(firstSector, SEEK_SET);
|
|
|
|
writeWavHeader(process);
|
|
while ((firstSector+count) <= lastSector) {
|
|
qint16 *buf = cdparanoia.read();
|
|
if (!buf) {
|
|
emit result(Device::Failed);
|
|
process.close();
|
|
return;
|
|
}
|
|
if (stopRequested) {
|
|
emit result(Device::Cancelled);
|
|
process.close();
|
|
return;
|
|
}
|
|
|
|
char *buffer=(char *)buf;
|
|
|
|
qint64 writePos=0;
|
|
do {
|
|
qint64 bytesWritten = process.write(&buffer[writePos], CD_FRAMESIZE_RAW - writePos);
|
|
if (stopRequested) {
|
|
emit result(Device::Cancelled);
|
|
process.close();
|
|
QFile::remove(destFile);
|
|
return;
|
|
}
|
|
if (-1==bytesWritten) {
|
|
emit result(Device::WriteFailed);
|
|
process.close();
|
|
QFile::remove(destFile);
|
|
return;
|
|
}
|
|
writePos+=bytesWritten;
|
|
} while (writePos<CD_FRAMESIZE_RAW);
|
|
|
|
count++;
|
|
setPercent((count*100/total)+0.5);
|
|
}
|
|
process.closeWriteChannel();
|
|
process.waitForFinished();
|
|
Utils::setFilePerms(destFile);
|
|
Tags::update(destFile, Song(), song, 3);
|
|
|
|
if (!stopRequested && !coverFile.isEmpty()) {
|
|
copiedCover=Covers::copyImage(Utils::getDir(coverFile), Utils::getDir(destFile), Utils::getFile(coverFile), Covers::albumFileName(song)+Utils::getExtension(coverFile), 0);
|
|
}
|
|
|
|
emit result(Device::Ok);
|
|
}
|
|
}
|
|
|
|
#include "moc_extractjob.cpp"
|