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