Make debug() not crash if recorderInstance hasn't been set
[skype-call-recorder.git] / mp3writer.cpp
blob2ecfe215f63ff5c495291dcd8b0caac7f954eb41
1 /*
2 Skype Call Recorder
3 Copyright (C) 2008 jlh (jlh at gmx dot ch)
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2 of the License, version 3 of
8 the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
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 St, Fifth Floor, Boston, MA 02110-1301 USA
19 The GNU General Public License version 2 is included with the source of
20 this program under the file name COPYING. You can also get a copy on
21 http://www.fsf.org/
24 #include <QByteArray>
25 #include <QString>
26 #include <lame/lame.h>
27 #include <id3/tag.h>
28 #include "mp3writer.h"
29 #include "common.h"
30 #include "preferences.h"
32 Mp3Writer::~Mp3Writer() {
35 bool Mp3Writer::open(const QString &fn, long sr, bool s) {
36 bool b = AudioFileWriter::open(fn + ".mp3", sr, s);
38 if (!b)
39 return false;
41 lame = lame_init();
42 if (!lame)
43 return false;
45 bitRate = preferences.get("output.format.mp3.bitrate").toInt();
47 lame_set_in_samplerate(lame, sampleRate);
48 lame_set_num_channels(lame, stereo ? 2 : 1);
49 lame_set_out_samplerate(lame, sampleRate);
50 // TODO: do we need this?
51 lame_set_bWriteVbrTag(lame, 0);
52 lame_set_mode(lame, stereo ? STEREO : MONO);
53 lame_set_brate(lame, bitRate);
54 if (lame_init_params(lame) == -1)
55 return false;
57 return true;
60 void Mp3Writer::close() {
61 AudioFileWriter::close();
62 writeTags();
65 namespace {
66 ID3_Frame *getOrCreateTag(ID3_Tag &tag, ID3_FrameID id) {
67 ID3_Frame *frame = tag.Find(id);
69 if (!frame) {
70 frame = new ID3_Frame(id);
71 tag.AttachFrame(frame);
74 return frame;
78 void Mp3Writer::writeTags() {
79 if (!mustWriteTags)
80 return;
82 debug("Writing tags to MP3 file");
84 QByteArray fn = QFile::encodeName(file.fileName());
85 ID3_Tag tag(fn.constData());
87 // NOTE: we don't set ID3FID_TITLE as the file name is already meant to
88 // be a good enough description of the content
90 QString str = tagTime.toString("yyyyddMMhhmm");
91 // TODO: the following would be better but doesn't work. find out why
92 //getOrCreateTag(tag, ID3FID_COMMENT )->GetField(ID3FN_TEXT)->Set(tagComment.utf16());
93 getOrCreateTag(tag, ID3FID_COMMENT )->GetField(ID3FN_TEXT)->Set(tagComment.toAscii().constData());
94 getOrCreateTag(tag, ID3FID_CONTENTTYPE)->GetField(ID3FN_TEXT)->Set("(101)Skype Call");
95 getOrCreateTag(tag, ID3FID_YEAR )->GetField(ID3FN_TEXT)->Set(str.mid(0, 4).toAscii().constData());
96 getOrCreateTag(tag, ID3FID_DATE )->GetField(ID3FN_TEXT)->Set(str.mid(4, 4).toAscii().constData());
97 getOrCreateTag(tag, ID3FID_TIME )->GetField(ID3FN_TEXT)->Set(str.mid(8, 4).toAscii().constData());
99 tag.Update();
100 mustWriteTags = false;
103 bool Mp3Writer::write(QByteArray &left, QByteArray &right, int samples, bool flush) {
104 int ret;
105 QByteArray output;
106 // rough upper bound formula taken from lame.h
107 int size = samples + samples / 4 + 7200;
109 do {
110 output.resize(size);
112 if (stereo) {
113 ret = lame_encode_buffer(lame, reinterpret_cast<const short *>(left.constData()),
114 reinterpret_cast<const short *>(right.constData()), samples,
115 reinterpret_cast<unsigned char *>(output.data()), output.size());
116 } else {
117 // lame.h claims to write to the buffers, even though they're declared const, be safe
118 // TODO: this mixes both channels again! can lame take only mono samples?
119 ret = lame_encode_buffer(lame, reinterpret_cast<const short *>(left.data()),
120 reinterpret_cast<const short *>(left.data()), samples,
121 reinterpret_cast<unsigned char *>(output.data()), output.size());
124 if (ret == -1) {
125 // there wasn't enough space in output
126 size *= 2;
127 continue;
129 } while (false);
131 if (ret < 0) {
132 debug(QString("Error while writing MP3 file, code = %1").arg(ret));
133 return false;
136 samplesWritten += samples;
138 if (ret > 0) {
139 output.truncate(ret);
140 file.write(output);
143 left.remove(0, samples * 2);
144 if (stereo)
145 right.remove(0, samples * 2);
147 if (!flush)
148 return true;
150 // flush mp3
152 output.resize(10240);
153 ret = lame_encode_flush(lame, reinterpret_cast<unsigned char *>(output.data()), output.size());
155 if (ret < 0) {
156 debug(QString("Error while flushing MP3 file, code = %1").arg(ret));
157 return false;
160 if (ret > 0) {
161 output.truncate(ret);
162 file.write(output);
165 lame_close(lame);
167 return true;