1 //=============================================================================
2 // MuseScore
3 // Linux Music Score Editor
4 //
5 // Copyright (C) 2011 Werner Schweer and others
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License version 2.
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
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 //=============================================================================
19
20 #include "exportmp3.h"
21
22 #include "libmscore/score.h"
23 #include "libmscore/note.h"
24 #include "libmscore/part.h"
25
26 #include "audio/midi/msynthesizer.h"
27 #include "mscore/preferences.h"
28
29 namespace Ms {
30
31 //---------------------------------------------------------
32 // MP3Exporter
33 //---------------------------------------------------------
34
MP3Exporter()35 MP3Exporter::MP3Exporter()
36 {
37 mLibraryLoaded = false;
38 mEncoding = false;
39 mGF = NULL;
40
41 QSettings settings;
42 mLibPath = settings.value("/Export/lameMP3LibPath", "").toString();
43
44 mBitrate = 128;
45 mQuality = QUALITY_2;
46 mChannel = CHANNEL_JOINT;
47 mMode = MODE_CBR;
48 mRoutine = ROUTINE_FAST;
49 }
50
~MP3Exporter()51 MP3Exporter::~MP3Exporter()
52 {
53 freeLibrary();
54 }
55
56 //---------------------------------------------------------
57 // findLibrary
58 //---------------------------------------------------------
59
findLibrary()60 bool MP3Exporter::findLibrary()
61 {
62 QString path;
63 QString name;
64
65 if (!mLibPath.isEmpty()) {
66 QFileInfo fi(mLibPath);
67 path = fi.absolutePath();
68 name = fi.completeBaseName();
69 }
70 else {
71 path = getLibraryPath();
72 name = getLibraryName();
73 }
74
75 if (MScore::noGui)
76 return false;
77
78 QString libPath = QFileDialog::getOpenFileName(
79 0, qApp->translate("MP3Exporter", "Where is %1 ?").arg(getLibraryName()),
80 path,
81 getLibraryTypeString(),
82 0,
83 preferences.getBool(PREF_UI_APP_USENATIVEDIALOGS) ? QFileDialog::Options() : QFileDialog::DontUseNativeDialog
84 );
85
86 if (libPath.isEmpty())
87 return false;
88
89 QFileInfo fp(libPath);
90 if (!fp.exists())
91 return false;
92
93 mLibPath = libPath;
94
95 QSettings settings;
96 settings.setValue("/Export/lameMP3LibPath", mLibPath);
97
98 return true;
99 }
100
101 //---------------------------------------------------------
102 // loadLibrary
103 //---------------------------------------------------------
104
loadLibrary(AskUser askuser)105 bool MP3Exporter::loadLibrary(AskUser askuser)
106 {
107 if (validLibraryLoaded()) {
108 freeLibrary();
109 mLibraryLoaded = false;
110 }
111
112 // First try loading it from a previously located path
113 if (!mLibPath.isEmpty()) {
114 qDebug("Attempting to load LAME from previously defined path");
115 mLibraryLoaded = initLibrary(mLibPath);
116 }
117
118 // If not successful, try loading using system search paths
119 if (!validLibraryLoaded()) {
120 qDebug("Attempting to load LAME from system search paths");
121 mLibPath = getLibraryName();
122 mLibraryLoaded = initLibrary(mLibPath);
123 }
124
125 // If not successful, try loading using compiled in path
126 if (!validLibraryLoaded()) {
127 qDebug("Attempting to load LAME from builtin path");
128 QFileInfo fn(QDir(getLibraryPath()), getLibraryName());
129 mLibPath = fn.absoluteFilePath();
130 mLibraryLoaded = initLibrary(mLibPath);
131 }
132
133 // If not successful, must ask the user
134 if (!validLibraryLoaded() && askuser != MP3Exporter::AskUser::NO) {
135 qDebug("(Maybe) ask user for library");
136 int ret = QMessageBox::question(0, qApp->translate("MP3Exporter", "Save as MP3"),
137 qApp->translate("MP3Exporter", "MuseScore does not export MP3 files directly, but instead uses "
138 "the freely available LAME library. You must obtain %1 "
139 "separately (for details check the handbook), and then locate the file for MuseScore.\n"
140 "You only need to do this once.\n\n"
141 "Would you like to locate %2 now?").arg(getLibraryName(), getLibraryName()),
142 QMessageBox::Yes|QMessageBox::No, QMessageBox::NoButton);
143 if (ret == QMessageBox::Yes && findLibrary()) {
144 mLibraryLoaded = initLibrary(mLibPath);
145 }
146 }
147
148 // Oh well, just give up
149 if (!validLibraryLoaded()) {
150 qDebug("Failed to locate LAME library");
151 return false;
152 }
153
154 qDebug("LAME library successfully loaded");
155 return true;
156 }
157
validLibraryLoaded()158 bool MP3Exporter::validLibraryLoaded()
159 {
160 return mLibraryLoaded;
161 }
162
setMode(int mode)163 void MP3Exporter::setMode(int mode)
164 {
165 mMode = mode;
166 }
167
setBitrate(int rate)168 void MP3Exporter::setBitrate(int rate)
169 {
170 mBitrate = rate;
171 }
172
setQuality(int q,int r)173 void MP3Exporter::setQuality(int q, int r)
174 {
175 mQuality = q;
176 mRoutine = r;
177 }
178
setChannel(int mode)179 void MP3Exporter::setChannel(int mode)
180 {
181 mChannel = mode;
182 }
183
184 //---------------------------------------------------------
185 // initLibrary
186 //---------------------------------------------------------
187
initLibrary(QString libpath)188 bool MP3Exporter::initLibrary(QString libpath)
189 {
190 qDebug("Loading LAME from %s", qPrintable(libpath));
191 lame_lib = new QLibrary(libpath, 0);
192 if (!lame_lib->load()) {
193 qDebug("load failed <%s>", qPrintable(lame_lib->errorString()));
194 return false;
195 }
196
197 lame_init = (lame_init_t *)
198 lame_lib->resolve("lame_init");
199 get_lame_version = (get_lame_version_t *)
200 lame_lib->resolve("get_lame_version");
201 lame_init_params = (lame_init_params_t *)
202 lame_lib->resolve("lame_init_params");
203 lame_encode_buffer_float = (lame_encode_buffer_float_t *)
204 lame_lib->resolve("lame_encode_buffer_float");
205 lame_encode_flush = (lame_encode_flush_t *)
206 lame_lib->resolve("lame_encode_flush");
207 lame_close = (lame_close_t *)
208 lame_lib->resolve("lame_close");
209
210 lame_set_in_samplerate = (lame_set_in_samplerate_t *)
211 lame_lib->resolve("lame_set_in_samplerate");
212 lame_set_out_samplerate = (lame_set_out_samplerate_t *)
213 lame_lib->resolve("lame_set_out_samplerate");
214 lame_set_num_channels = (lame_set_num_channels_t *)
215 lame_lib->resolve("lame_set_num_channels");
216 lame_set_quality = (lame_set_quality_t *)
217 lame_lib->resolve("lame_set_quality");
218 lame_set_brate = (lame_set_brate_t *)
219 lame_lib->resolve("lame_set_brate");
220 lame_set_VBR = (lame_set_VBR_t *)
221 lame_lib->resolve("lame_set_VBR");
222 lame_set_VBR_q = (lame_set_VBR_q_t *)
223 lame_lib->resolve("lame_set_VBR_q");
224 lame_set_VBR_min_bitrate_kbps = (lame_set_VBR_min_bitrate_kbps_t *)
225 lame_lib->resolve("lame_set_VBR_min_bitrate_kbps");
226 lame_set_mode = (lame_set_mode_t *)
227 lame_lib->resolve("lame_set_mode");
228 lame_set_preset = (lame_set_preset_t *)
229 lame_lib->resolve("lame_set_preset");
230 lame_set_error_protection = (lame_set_error_protection_t *)
231 lame_lib->resolve("lame_set_error_protection");
232 lame_set_disable_reservoir = (lame_set_disable_reservoir_t *)
233 lame_lib->resolve("lame_set_disable_reservoir");
234 lame_set_padding_type = (lame_set_padding_type_t *)
235 lame_lib->resolve("lame_set_padding_type");
236 lame_set_bWriteVbrTag = (lame_set_bWriteVbrTag_t *)
237 lame_lib->resolve("lame_set_bWriteVbrTag");
238
239 // These are optional
240 lame_get_lametag_frame = (lame_get_lametag_frame_t *)
241 lame_lib->resolve("lame_get_lametag_frame");
242 lame_mp3_tags_fid = (lame_mp3_tags_fid_t *)
243 lame_lib->resolve("lame_mp3_tags_fid");
244 #if defined(Q_OS_WIN)
245 beWriteInfoTag = (beWriteInfoTag_t *)
246 lame_lib->resolve("beWriteInfoTag");
247 beVersion = (beVersion_t *)
248 lame_lib->resolve("beVersion");
249 #endif
250
251 if (!lame_init ||
252 !get_lame_version ||
253 !lame_init_params ||
254 !lame_encode_buffer_float ||
255 !lame_encode_flush ||
256 !lame_close ||
257 !lame_set_in_samplerate ||
258 !lame_set_out_samplerate ||
259 !lame_set_num_channels ||
260 !lame_set_quality ||
261 !lame_set_brate ||
262 !lame_set_VBR ||
263 !lame_set_VBR_q ||
264 !lame_set_mode ||
265 !lame_set_preset ||
266 !lame_set_error_protection ||
267 !lame_set_disable_reservoir ||
268 !lame_set_padding_type ||
269 !lame_set_bWriteVbrTag) {
270 qDebug("Failed to find a required symbol in the LAME library");
271 #if defined(Q_OS_WIN)
272 if (beVersion) {
273 be_version v;
274 beVersion(&v);
275
276 mBladeVersion = QString("You are linking to lame_enc.dll v%d.%d. This version is not compatible with MuseScore %d.\nPlease download the latest version of the LAME MP3 library.")
277 .arg(v.byMajorVersion)
278 .arg(v.byMinorVersion)
279 .arg(1); //TODO
280 }
281 #endif
282
283 lame_lib->unload();
284 delete lame_lib;
285 return false;
286 }
287
288 mGF = lame_init();
289 if (mGF == NULL) {
290 lame_lib->unload();
291 delete lame_lib;
292 return false;
293 }
294
295 return true;
296 }
297
298 //---------------------------------------------------------
299 // freeLibrary
300 //---------------------------------------------------------
301
freeLibrary()302 void MP3Exporter::freeLibrary()
303 {
304 if (mGF) {
305 lame_close(mGF);
306 mGF = NULL;
307 lame_lib->unload();
308 delete lame_lib;
309 }
310 return;
311 }
312
313 //---------------------------------------------------------
314 // getLibraryVersion
315 //---------------------------------------------------------
316
getLibraryVersion()317 QString MP3Exporter::getLibraryVersion()
318 {
319 if (!mLibraryLoaded)
320 return QString("");
321 return QString("LAME %s").arg(get_lame_version());
322 }
323
324 //---------------------------------------------------------
325 // initializeStream
326 //---------------------------------------------------------
327
initializeStream(int channels,int sampleRate)328 int MP3Exporter::initializeStream(int channels, int sampleRate)
329 {
330 if (!mLibraryLoaded)
331 return -1;
332
333 if (channels > 2)
334 return -1;
335
336 lame_set_error_protection(mGF, false);
337 lame_set_num_channels(mGF, channels);
338 lame_set_in_samplerate(mGF, sampleRate);
339 lame_set_out_samplerate(mGF, sampleRate);
340 lame_set_disable_reservoir(mGF, true);
341 lame_set_padding_type(mGF, PAD_NO);
342
343 // Add the VbrTag for all types. For ABR/VBR, a Xing tag will be created.
344 // For CBR, it will be a Lame Info tag.
345 lame_set_bWriteVbrTag(mGF, true);
346
347 // Set the VBR quality or ABR/CBR bitrate
348 switch (mMode) {
349 case MODE_SET:
350 {
351 int preset;
352
353 if (mQuality == PRESET_INSANE)
354 preset = INSANE;
355 else if (mRoutine == ROUTINE_FAST) {
356 if (mQuality == PRESET_EXTREME)
357 preset = EXTREME_FAST;
358 else if (mQuality == PRESET_STANDARD)
359 preset = STANDARD_FAST;
360 else
361 preset = 1007; // Not defined until 3.96
362 }
363 else {
364 if (mQuality == PRESET_EXTREME)
365 preset = EXTREME;
366 else if (mQuality == PRESET_STANDARD)
367 preset = STANDARD;
368 else
369 preset = 1006; // Not defined until 3.96
370 }
371 lame_set_preset(mGF, preset);
372 }
373 break;
374
375 case MODE_VBR:
376 lame_set_VBR(mGF, (mRoutine == ROUTINE_STANDARD ? vbr_rh : vbr_mtrh ));
377 lame_set_VBR_q(mGF, mQuality);
378 break;
379
380 case MODE_ABR:
381 lame_set_preset(mGF, mBitrate );
382 break;
383
384 default:
385 lame_set_VBR(mGF, vbr_off);
386 lame_set_brate(mGF, mBitrate);
387 break;
388 }
389
390 // Set the channel mode
391 MPEG_mode mode;
392 if (channels == 1)
393 mode = MONO;
394 else if (mChannel == CHANNEL_JOINT)
395 mode = JOINT_STEREO;
396 else
397 mode = STEREO;
398 lame_set_mode(mGF, mode);
399
400 int rc = lame_init_params(mGF);
401 if (rc < 0)
402 return rc;
403
404 #if 0
405 dump_config(mGF);
406 #endif
407
408 mInfoTagLen = 0;
409 mEncoding = true;
410
411 return mSamplesPerChunk;
412 }
413
414 //---------------------------------------------------------
415 // getOutBufferSize
416 //---------------------------------------------------------
417
getOutBufferSize()418 int MP3Exporter::getOutBufferSize()
419 {
420 if (!mEncoding)
421 return -1;
422
423 return mOutBufferSize;
424 }
425
426 //---------------------------------------------------------
427 // bufferPreamp
428 //---------------------------------------------------------
429
bufferPreamp(float buffer[],int nSamples)430 void MP3Exporter::bufferPreamp(float buffer[], int nSamples)
431 {
432 for (int i = 0; i < nSamples; i++)
433 buffer[i] = buffer[i] * 32768;
434 }
435
436 //---------------------------------------------------------
437 // encodeBuffer
438 //---------------------------------------------------------
439
encodeBuffer(float inbufferL[],float inbufferR[],unsigned char outbuffer[])440 int MP3Exporter::encodeBuffer(float inbufferL[], float inbufferR[], unsigned char outbuffer[])
441 {
442 if (!mEncoding)
443 return -1;
444
445 bufferPreamp(inbufferL, mSamplesPerChunk);
446 bufferPreamp(inbufferR, mSamplesPerChunk);
447 return lame_encode_buffer_float(mGF, inbufferL, inbufferR, mSamplesPerChunk,
448 outbuffer, mOutBufferSize);
449 }
450
451 //---------------------------------------------------------
452 // encodeRemainder
453 //---------------------------------------------------------
454
encodeRemainder(float inbufferL[],float inbufferR[],int nSamples,unsigned char outbuffer[])455 int MP3Exporter::encodeRemainder(float inbufferL[], float inbufferR[], int nSamples,
456 unsigned char outbuffer[])
457 {
458 if (!mEncoding)
459 return -1;
460
461 bufferPreamp(inbufferL, nSamples);
462 bufferPreamp(inbufferR, nSamples);
463 return lame_encode_buffer_float(mGF, inbufferL, inbufferR, nSamples, outbuffer,
464 mOutBufferSize);
465 }
466
467 //---------------------------------------------------------
468 // encodeBufferMono
469 //---------------------------------------------------------
470
encodeBufferMono(float inbuffer[],unsigned char outbuffer[])471 int MP3Exporter::encodeBufferMono(float inbuffer[], unsigned char outbuffer[])
472 {
473 if (!mEncoding)
474 return -1;
475
476 bufferPreamp(inbuffer, mSamplesPerChunk);
477 return lame_encode_buffer_float(mGF, inbuffer, inbuffer, mSamplesPerChunk,
478 outbuffer, mOutBufferSize);
479 }
480
481 //---------------------------------------------------------
482 // encodeRemainderMono
483 //---------------------------------------------------------
484
encodeRemainderMono(float inbuffer[],int nSamples,unsigned char outbuffer[])485 int MP3Exporter::encodeRemainderMono(float inbuffer[], int nSamples,
486 unsigned char outbuffer[])
487 {
488 if (!mEncoding)
489 return -1;
490
491 bufferPreamp(inbuffer, nSamples);
492 return lame_encode_buffer_float(mGF, inbuffer, inbuffer, nSamples, outbuffer,
493 mOutBufferSize);
494 }
495
496 //---------------------------------------------------------
497 // finishStream
498 //---------------------------------------------------------
499
finishStream(unsigned char outbuffer[])500 int MP3Exporter::finishStream(unsigned char outbuffer[])
501 {
502 if (!mEncoding)
503 return -1;
504
505 mEncoding = false;
506 int result = lame_encode_flush(mGF, outbuffer, mOutBufferSize);
507
508 if (lame_get_lametag_frame)
509 mInfoTagLen = lame_get_lametag_frame(mGF, mInfoTagBuf, sizeof(mInfoTagBuf));
510 return result;
511 }
512
513 //---------------------------------------------------------
514 // cancelEncoding
515 //---------------------------------------------------------
516
cancelEncoding()517 void MP3Exporter::cancelEncoding()
518 {
519 mEncoding = false;
520 }
521
522 /*void MP3Exporter::PutInfoTag(QFile f, qint64 off)
523 {
524 QDataStream out(&f);
525 if (mGF) {
526 if (mInfoTagLen > 0) {
527 out.skipRawData (off);
528 out.writeRawData(mInfoTagBuf, mInfoTagLen);
529 }
530 #if defined(Q_OS_WIN)
531 else if (beWriteInfoTag) {
532 f.flush();
533 QFileInfo fi(f);
534 beWriteInfoTag(mGF, qPrintable(fi.completeBaseName()));
535 mGF = NULL;
536 }
537 #endif
538 else if (lame_mp3_tags_fid) {
539 std::FILE *fp;
540 if ((fp = std::fdopen(file.handle(), "w+")) != NULL)
541 lame_mp3_tags_fid(mGF, fp);
542 }
543 }
544
545 f.seek(f.size());
546 }*/
547
548 #if defined(Q_OS_WIN)
549 /* values for Windows */
550
getLibraryPath()551 QString MP3Exporter::getLibraryPath()
552 {
553 QSettings settings("HKEY_LOCAL_MACHINE\\Software\\Lame for Audacity", QSettings::NativeFormat);
554 QString sReturnedValue = settings.value( "InstallPath", "" ).toString();
555 if (! sReturnedValue.isEmpty()) {
556 return sReturnedValue;
557 }
558 return QDir::rootPath();
559 }
560
getLibraryName()561 QString MP3Exporter::getLibraryName()
562 {
563 return QString("lame_enc.dll");
564 }
565
getLibraryTypeString()566 QString MP3Exporter::getLibraryTypeString()
567 {
568 return QString("Only lame_enc.dll (lame_enc.dll);;Dynamically Linked Libraries (*.dll);;All Files (*.*)");
569 }
570
571 #elif defined(Q_OS_MAC)
572 /* values for Mac OS X */
573
getLibraryPath()574 QString MP3Exporter::getLibraryPath()
575 {
576 return QString("%1/../Resources/Frameworks/").arg(qApp->applicationDirPath());
577 }
578
getLibraryName()579 QString MP3Exporter::getLibraryName()
580 {
581 return QString("libmp3lame.dylib");
582 }
583
getLibraryTypeString()584 QString MP3Exporter::getLibraryTypeString()
585 {
586 return QString("Only libmp3lame.dylib (libmp3lame.dylib);;Dynamic Libraries (*.dylib);;All Files (*)");
587 }
588
589 #else //!Q_OS_MAC
590 /* Values for Linux / Unix systems */
591
getLibraryPath()592 QString MP3Exporter::getLibraryPath()
593 {
594 return QString("/usr/lib");
595 }
596
getLibraryName()597 QString MP3Exporter::getLibraryName()
598 {
599 return QString("libmp3lame.so.0");
600 }
601
getLibraryTypeString()602 QString MP3Exporter::getLibraryTypeString()
603 {
604 return QString("Only libmp3lame.so.0 (libmp3lame.so.0);;Primary Shared Object files (*.so);;Extended Libraries (*.so*);;All Files (*)");
605 }
606 #endif //mac
607
608 }
609
610