OSDN Git Service

More FLAC workarounds. Using "--channel-map=none" will fix most cases, although we...
[lamexp/LameXP.git] / src / Encoder_FLAC.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2012 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (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 General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 //
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
21
22 #include "Encoder_FLAC.h"
23
24 #include "Global.h"
25 #include "Model_Settings.h"
26
27 #include <QProcess>
28 #include <QDir>
29
30 FLACEncoder::FLACEncoder(void)
31 :
32         m_binary(lamexp_lookup_tool("flac.exe"))
33 {
34         if(m_binary.isEmpty())
35         {
36                 throw "Error initializing FLAC encoder. Tool 'flac.exe' is not registred!";
37         }
38 }
39
40 FLACEncoder::~FLACEncoder(void)
41 {
42 }
43
44 bool FLACEncoder::encode(const QString &sourceFile, const AudioFileModel &metaInfo, const QString &outputFile, volatile bool *abortFlag)
45 {
46         QProcess process;
47         QStringList args;
48
49         args << QString("-%1").arg(QString::number(qMax(0, qMin(8, m_configBitrate))));
50         args << "--channel-map=none";
51
52         if(!metaInfo.fileName().isEmpty()) args << "-T" << QString("title=%1").arg(metaInfo.fileName());
53         if(!metaInfo.fileArtist().isEmpty()) args << "-T" << QString("artist=%1").arg(metaInfo.fileArtist());
54         if(!metaInfo.fileAlbum().isEmpty()) args << "-T" << QString("album=%1").arg(metaInfo.fileAlbum());
55         if(!metaInfo.fileGenre().isEmpty()) args << "-T" << QString("genre=%1").arg(metaInfo.fileGenre());
56         if(!metaInfo.fileComment().isEmpty()) args << "-T" << QString("comment=%1").arg(metaInfo.fileComment());
57         if(metaInfo.fileYear()) args << "-T" << QString("date=%1").arg(QString::number(metaInfo.fileYear()));
58         if(metaInfo.filePosition()) args << "-T" << QString("track=%1").arg(QString::number(metaInfo.filePosition()));
59         if(!metaInfo.fileCover().isEmpty()) args << QString("--picture=%1").arg(metaInfo.fileCover());
60
61         //args << "--tv" << QString().sprintf("Encoder=LameXP v%d.%02d.%04d [%s]", lamexp_version_major(), lamexp_version_minor(), lamexp_version_build(), lamexp_version_release());
62
63         if(!m_configCustomParams.isEmpty()) args << m_configCustomParams.split(" ", QString::SkipEmptyParts);
64
65         args << "-f" << "-o" << QDir::toNativeSeparators(outputFile);
66         args << QDir::toNativeSeparators(sourceFile);
67
68         if(!startProcess(process, m_binary, args))
69         {
70                 return false;
71         }
72
73         bool bTimeout = false;
74         bool bAborted = false;
75         int prevProgress = -1;
76
77         QRegExp regExp("\\s(\\d+)% complete");
78
79         while(process.state() != QProcess::NotRunning)
80         {
81                 if(*abortFlag)
82                 {
83                         process.kill();
84                         bAborted = true;
85                         emit messageLogged("\nABORTED BY USER !!!");
86                         break;
87                 }
88                 process.waitForReadyRead(m_processTimeoutInterval);
89                 if(!process.bytesAvailable() && process.state() == QProcess::Running)
90                 {
91                         process.kill();
92                         qWarning("FLAC process timed out <-- killing!");
93                         emit messageLogged("\nPROCESS TIMEOUT !!!");
94                         bTimeout = true;
95                         break;
96                 }
97                 while(process.bytesAvailable() > 0)
98                 {
99                         QByteArray line = process.readLine();
100                         QString text = QString::fromUtf8(line.constData()).simplified();
101                         if(regExp.lastIndexIn(text) >= 0)
102                         {
103                                 bool ok = false;
104                                 int progress = regExp.cap(1).toInt(&ok);
105                                 if(ok && (progress > prevProgress))
106                                 {
107                                         emit statusUpdated(progress);
108                                         prevProgress = qMin(progress + 2, 99);
109                                 }
110                         }
111                         else if(!text.isEmpty())
112                         {
113                                 emit messageLogged(text);
114                         }
115                 }
116         }
117
118         process.waitForFinished();
119         if(process.state() != QProcess::NotRunning)
120         {
121                 process.kill();
122                 process.waitForFinished(-1);
123         }
124         
125         emit statusUpdated(100);
126         emit messageLogged(QString().sprintf("\nExited with code: 0x%04X", process.exitCode()));
127
128         if(bTimeout || bAborted || process.exitCode() != EXIT_SUCCESS)
129         {
130                 return false;
131         }
132         
133         return true;
134 }
135
136 QString FLACEncoder::extension(void)
137 {
138         return "flac";
139 }
140
141 bool FLACEncoder::isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion)
142 {
143         if(containerType.compare("Wave", Qt::CaseInsensitive) == 0)
144         {
145                 if(formatType.compare("PCM", Qt::CaseInsensitive) == 0)
146                 {
147                         return true;
148                 }
149         }
150
151         return false;
152 }
153
154 const unsigned int *FLACEncoder::supportedChannelCount(void)
155 {
156         static const unsigned int supportedChannels[] = {2, 4, 5, 6, 7, 8, NULL};
157         return supportedChannels;
158 }
159
160 const unsigned int *FLACEncoder::supportedBitdepths(void)
161 {
162         static const unsigned int supportedBPS[] = {16, 24, NULL};
163         return supportedBPS;
164 }