1 /*************************************************************************
2         FlacDecoder.cpp  -  decoder for FLAC data
3                              -------------------
4     begin                : Tue Feb 28 2004
5     copyright            : (C) 2004 by Thomas Eschenbacher
6     email                : Thomas.Eschenbacher@gmx.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include "config.h"
19 
20 #include <new>
21 
22 #include <QDateTime>
23 
24 #include <KLocalizedString>
25 
26 #include "libkwave/Compression.h"
27 #include "libkwave/MessageBox.h"
28 #include "libkwave/MultiWriter.h"
29 #include "libkwave/Sample.h"
30 #include "libkwave/String.h"
31 #include "libkwave/Writer.h"
32 
33 #include "FlacCodecPlugin.h"
34 #include "FlacDecoder.h"
35 
36 //***************************************************************************
FlacDecoder()37 Kwave::FlacDecoder::FlacDecoder()
38     :Kwave::Decoder(),
39      FLAC::Decoder::Stream(),
40      m_source(Q_NULLPTR),
41      m_dest(Q_NULLPTR),
42      m_vorbis_comment_map()
43 {
44     REGISTER_MIME_TYPES
45     REGISTER_COMPRESSION_TYPES
46 }
47 
48 //***************************************************************************
~FlacDecoder()49 Kwave::FlacDecoder::~FlacDecoder()
50 {
51     if (m_source) close();
52 }
53 
54 //***************************************************************************
instance()55 Kwave::Decoder *Kwave::FlacDecoder::instance()
56 {
57     return new(std::nothrow) Kwave::FlacDecoder();
58 }
59 
60 //***************************************************************************
read_callback(FLAC__byte buffer[],size_t * bytes)61 ::FLAC__StreamDecoderReadStatus Kwave::FlacDecoder::read_callback(
62         FLAC__byte buffer[], size_t *bytes)
63 {
64     Q_ASSERT(bytes);
65     Q_ASSERT(m_source);
66     if (!bytes || !m_source) return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
67 
68     // check for EOF
69     if (m_source->atEnd()) {
70 	*bytes = 0;
71 	return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
72     }
73 
74     // read into application buffer
75     *bytes = static_cast<unsigned>(m_source->read(
76         reinterpret_cast<char *>(&(buffer[0])),
77         static_cast<qint64>(*bytes)
78     ));
79 
80     if (!*bytes) return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
81 
82     return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
83 }
84 
85 //***************************************************************************
write_callback(const::FLAC__Frame * frame,const FLAC__int32 * const buffer[])86 ::FLAC__StreamDecoderWriteStatus Kwave::FlacDecoder::write_callback(
87         const ::FLAC__Frame *frame,
88         const FLAC__int32 * const buffer[])
89 {
90     Q_ASSERT(buffer);
91     Q_ASSERT(frame);
92     Q_ASSERT(m_dest);
93     if (!buffer || !frame || !m_dest)
94         return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
95 
96     const unsigned int samples = frame->header.blocksize;
97 
98     const unsigned int tracks  = Kwave::FileInfo(metaData()).tracks();
99     Q_ASSERT(samples);
100     Q_ASSERT(tracks);
101     if (!samples || !tracks)
102         return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
103 
104     Kwave::SampleArray dst(samples);
105 
106     // expand the samples up to the correct number of bits
107     int shift = SAMPLE_BITS - Kwave::FileInfo(metaData()).bits();
108     if (shift < 0) shift = 0;
109     unsigned int mul = (1 << shift);
110 
111     // decode the samples into a temporary buffer and
112     // flush it to the Writer(s), track by track
113     for (unsigned int track=0; track < tracks; track++) {
114 	Kwave::Writer *writer = (*m_dest)[track];
115 	Q_ASSERT(writer);
116 	if (!writer) continue;
117 	const FLAC__int32 *src = buffer[track];
118 	sample_t *d = dst.data();
119 
120 	for (unsigned int sample = 0; sample < samples; sample++) {
121 	    // the following cast is only necessary if
122 	    // sample_t is not equal to a quint32
123 	    sample_t s  = static_cast<sample_t>(*src++);
124 
125 	    // correct precision
126 	    if (shift) s *= mul;
127 
128 	    // write to destination buffer
129 	    *d++ = s;
130 	}
131 
132 	// flush the temporary buffer
133 	(*writer) << dst;
134     }
135 
136     // at this point we check for a user-cancel
137     return (m_dest->isCanceled()) ?
138 	FLAC__STREAM_DECODER_WRITE_STATUS_ABORT :
139 	FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
140 }
141 
142 //***************************************************************************
parseStreamInfo(const FLAC::Metadata::StreamInfo & stream_info)143 void Kwave::FlacDecoder::parseStreamInfo(
144     const FLAC::Metadata::StreamInfo &stream_info)
145 {
146     qDebug("FLAC stream info");
147     qDebug("\tmin_blocksize   = %d", stream_info.get_min_blocksize());
148     qDebug("\tmax_blocksize   = %d", stream_info.get_max_blocksize());
149     qDebug("\tmin_framesize   = %d", stream_info.get_min_framesize());
150     qDebug("\tmax_framesize   = %d", stream_info.get_max_framesize());
151 
152     Kwave::FileInfo info(metaData());
153     info.setRate(stream_info.get_sample_rate());
154     info.setTracks(stream_info.get_channels());
155     info.setBits(stream_info.get_bits_per_sample());
156     info.setLength(stream_info.get_total_samples());
157     metaData().replace(Kwave::MetaDataList(info));
158 
159     qDebug("Bitstream is %u channel, %uHz",
160            stream_info.get_channels(),
161 	   stream_info.get_sample_rate());
162 }
163 
164 //***************************************************************************
parseVorbisComments(const FLAC::Metadata::VorbisComment & vorbis_comments)165 void Kwave::FlacDecoder::parseVorbisComments(
166         const FLAC::Metadata::VorbisComment &vorbis_comments)
167 {
168     Kwave::FileInfo info(metaData());
169 
170     // first of all: the vendor string, specifying the software
171     QString vendor = QString::fromUtf8(reinterpret_cast<const char *>(
172 	vorbis_comments.get_vendor_string()));
173     if (vendor.length()) {
174 	info.set(Kwave::INF_SOFTWARE, vendor);
175 	qDebug("Encoded by: '%s'\n\n", DBG(vendor));
176     }
177 
178     // parse all vorbis comments into Kwave file properties
179     for (unsigned int i = 0; i < vorbis_comments.get_num_comments(); i++) {
180 	FLAC::Metadata::VorbisComment::Entry comment =
181 	    vorbis_comments.get_comment(i);
182 	Q_ASSERT(comment.is_valid());
183 	if (!comment.is_valid()) continue;
184 
185 	QString name = QString::fromUtf8(
186 	    comment.get_field_name(), comment.get_field_name_length());
187 	QString value = QString::fromUtf8(
188 	    comment.get_field_value(), comment.get_field_value_length());
189 
190 	if (!m_vorbis_comment_map.contains(name)) continue;
191 
192 	// we have a known vorbis tag
193 	Kwave::FileProperty prop = m_vorbis_comment_map[name];
194 	info.set(prop, value);
195     }
196 
197     // convert the date property to a QDate
198     if (info.contains(Kwave::INF_CREATION_DATE)) {
199 	QString str_date =
200 	    QVariant(info.get(Kwave::INF_CREATION_DATE)).toString();
201 	QDate date;
202 	date = QDate::fromString(str_date, Qt::ISODate);
203 	if (!date.isValid()) {
204 	    int year = str_date.toInt();
205 	    date.setDate(year, 1, 1);
206 	}
207 	if (date.isValid()) info.set(Kwave::INF_CREATION_DATE, date);
208      }
209 
210      metaData().replace(Kwave::MetaDataList(info));
211 }
212 
213 //***************************************************************************
metadata_callback(const::FLAC__StreamMetadata * metadata)214 void Kwave::FlacDecoder::metadata_callback(
215     const ::FLAC__StreamMetadata *metadata)
216 {
217     Q_ASSERT(metadata);
218     if (!metadata) return;
219 
220     switch (metadata->type) {
221 	case FLAC__METADATA_TYPE_STREAMINFO: {
222 	    FLAC::Metadata::StreamInfo stream_info(
223 	        const_cast< ::FLAC__StreamMetadata * >(metadata), true);
224 	    parseStreamInfo(stream_info);
225 	    break;
226 	}
227 	case FLAC__METADATA_TYPE_PADDING:
228 	    // -> ignored
229 	    break;
230 	case FLAC__METADATA_TYPE_APPLICATION:
231 	    qDebug("FLAC metadata: application data");
232 	    break;
233 	case FLAC__METADATA_TYPE_SEEKTABLE:
234 	    qDebug("FLAC metadata: seektable - not supported yet");
235 	    break;
236 	case FLAC__METADATA_TYPE_VORBIS_COMMENT: {
237 	    FLAC::Metadata::VorbisComment vorbis_comments(
238 	        const_cast< ::FLAC__StreamMetadata * >(metadata), true);
239 	    parseVorbisComments(vorbis_comments);
240 	    break;
241 	}
242 	case FLAC__METADATA_TYPE_CUESHEET:
243 	    qDebug("FLAC metadata: cuesheet - not supported yet");
244 	    break;
245 	case FLAC__METADATA_TYPE_UNDEFINED:
246 	default:
247 	    qDebug("FLAC metadata: unknown/undefined type");
248     }
249 }
250 
251 //***************************************************************************
error_callback(::FLAC__StreamDecoderErrorStatus status)252 void Kwave::FlacDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
253 {
254     qDebug("FlacDecoder::error_callback: status=%d", status);
255 }
256 
257 //***************************************************************************
open(QWidget * widget,QIODevice & src)258 bool Kwave::FlacDecoder::open(QWidget *widget, QIODevice &src)
259 {
260     metaData().clear();
261     Q_ASSERT(!m_source);
262     if (m_source) qWarning("FlacDecoder::open(), already open !");
263 
264     // try to open the source
265     if (!src.open(QIODevice::ReadOnly)) {
266 	qWarning("failed to open source !");
267 	return false;
268     }
269 
270     // take over the source
271     m_source = &src;
272 
273     /********** Decoder setup ************/
274     qDebug("--- FlacDecoder::open() ---");
275     set_metadata_respond_all();
276 
277     // initialize the stream
278     FLAC__StreamDecoderInitStatus init_state = init();
279     if (init_state > FLAC__STREAM_DECODER_INIT_STATUS_OK) {
280         Kwave::MessageBox::error(widget, i18n(
281            "Opening the FLAC bitstream failed."));
282         return false;
283     }
284 
285     // read in all metadata
286     process_until_end_of_metadata();
287 
288     FLAC::Decoder::Stream::State state = get_state();
289     if (state >= FLAC__STREAM_DECODER_END_OF_STREAM) {
290 	Kwave::MessageBox::error(widget, i18n(
291 	   "Error while parsing the FLAC metadata. (%s)"),
292 	   _(state.as_cstring()));
293 	return false;
294     }
295 
296     // set some more standard properties
297     Kwave::FileInfo info(metaData());
298     info.set(Kwave::INF_MIMETYPE, _(DEFAULT_MIME_TYPE));
299     info.set(Kwave::INF_COMPRESSION, Kwave::Compression::FLAC);
300     metaData().replace(Kwave::MetaDataList(info));
301 
302     return true;
303 }
304 
305 //***************************************************************************
decode(QWidget *,Kwave::MultiWriter & dst)306 bool Kwave::FlacDecoder::decode(QWidget * /* widget */,
307                                 Kwave::MultiWriter &dst)
308 {
309     Q_ASSERT(m_source);
310     if (!m_source) return false;
311 
312     m_dest = &dst;
313 
314     // read in all remaining data
315     qDebug("FlacDecoder::decode(...)");
316     process_until_end_of_stream();
317 
318     m_dest = Q_NULLPTR;
319     Kwave::FileInfo info(metaData());
320     info.setLength(dst.last() ? (dst.last() + 1) : 0);
321     metaData().replace(Kwave::MetaDataList(info));
322 
323     // return with a valid Signal, even if the user pressed cancel !
324     return true;
325 }
326 
327 //***************************************************************************
close()328 void Kwave::FlacDecoder::close()
329 {
330     finish();
331     m_source = Q_NULLPTR;
332 }
333 
334 //***************************************************************************
335 //***************************************************************************
336