2012-05-26 14:49:10 +02:00
//=============================================================================
// MuseScore
// Linux Music Score Editor
// $Id: MP3Exporter.cpp 2992 2010-04-22 14:42:39Z lasconic $
//
// Copyright (C) 2011 Werner Schweer and others
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================
# include "libmscore/score.h"
2013-04-02 20:46:07 +02:00
# include "synthesizer/msynthesizer.h"
2012-05-26 14:49:10 +02:00
# include "libmscore/note.h"
# include "musescore.h"
# include "libmscore/part.h"
# include "preferences.h"
# include "exportmp3.h"
2013-05-13 18:49:17 +02:00
namespace Ms {
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
// MP3Exporter
//---------------------------------------------------------
MP3Exporter : : MP3Exporter ( )
{
mLibraryLoaded = false ;
mEncoding = false ;
mGF = NULL ;
QSettings settings ;
mLibPath = settings . value ( " /Export/lameMP3LibPath " , " " ) . toString ( ) ;
mBitrate = 128 ;
mQuality = QUALITY_2 ;
2015-03-19 18:43:03 +01:00
mChannel = CHANNEL_JOINT ;
2012-05-26 14:49:10 +02:00
mMode = MODE_CBR ;
mRoutine = ROUTINE_FAST ;
}
MP3Exporter : : ~ MP3Exporter ( )
{
freeLibrary ( ) ;
}
//---------------------------------------------------------
// findLibrary
//---------------------------------------------------------
bool MP3Exporter : : findLibrary ( )
{
QString path ;
QString name ;
if ( ! mLibPath . isEmpty ( ) ) {
QFileInfo fi ( mLibPath ) ;
path = fi . absolutePath ( ) ;
2015-12-16 10:24:34 +01:00
name = fi . completeBaseName ( ) ;
2012-05-26 14:49:10 +02:00
}
else {
path = getLibraryPath ( ) ;
name = getLibraryName ( ) ;
}
2014-02-28 11:14:43 +01:00
if ( MScore : : noGui )
2012-05-26 14:49:10 +02:00
return false ;
QString libPath = QFileDialog : : getOpenFileName (
2013-03-01 17:14:21 +01:00
0 , qApp - > translate ( " MP3Exporter " , " Where is %1 ? " ) . arg ( getLibraryName ( ) ) ,
2012-05-26 14:49:10 +02:00
path ,
2017-06-22 16:02:52 +02:00
getLibraryTypeString ( ) ,
0 ,
2017-11-29 08:21:36 +01:00
preferences . getBool ( PREF_UI_APP_USENATIVEDIALOGS ) ? QFileDialog : : Options ( ) : QFileDialog : : DontUseNativeDialog
2017-06-22 16:02:52 +02:00
) ;
2012-05-26 14:49:10 +02:00
if ( libPath . isEmpty ( ) )
return false ;
QFileInfo fp ( libPath ) ;
if ( ! fp . exists ( ) )
return false ;
mLibPath = libPath ;
QSettings settings ;
settings . setValue ( " /Export/lameMP3LibPath " , mLibPath ) ;
return true ;
}
//---------------------------------------------------------
// loadLibrary
//---------------------------------------------------------
bool MP3Exporter : : loadLibrary ( AskUser askuser )
{
if ( validLibraryLoaded ( ) ) {
freeLibrary ( ) ;
mLibraryLoaded = false ;
}
// First try loading it from a previously located path
if ( ! mLibPath . isEmpty ( ) ) {
2014-03-25 13:33:47 +01:00
qDebug ( " Attempting to load LAME from previously defined path " ) ;
2012-05-26 14:49:10 +02:00
mLibraryLoaded = initLibrary ( mLibPath ) ;
}
// If not successful, try loading using system search paths
if ( ! validLibraryLoaded ( ) ) {
2014-03-25 13:33:47 +01:00
qDebug ( " Attempting to load LAME from system search paths " ) ;
2012-05-26 14:49:10 +02:00
mLibPath = getLibraryName ( ) ;
mLibraryLoaded = initLibrary ( mLibPath ) ;
}
// If not successful, try loading using compiled in path
if ( ! validLibraryLoaded ( ) ) {
2014-03-25 13:33:47 +01:00
qDebug ( " Attempting to load LAME from builtin path " ) ;
2012-05-26 14:49:10 +02:00
QFileInfo fn ( QDir ( getLibraryPath ( ) ) , getLibraryName ( ) ) ;
mLibPath = fn . absoluteFilePath ( ) ;
mLibraryLoaded = initLibrary ( mLibPath ) ;
}
// If not successful, must ask the user
2017-03-20 15:53:06 +01:00
if ( ! validLibraryLoaded ( ) & & askuser ! = MP3Exporter : : AskUser : : NO ) {
2014-03-25 13:33:47 +01:00
qDebug ( " (Maybe) ask user for library " ) ;
2013-03-01 17:14:21 +01:00
int ret = QMessageBox : : question ( 0 , qApp - > translate ( " MP3Exporter " , " Save as MP3 " ) ,
2015-02-10 19:37:17 +01:00
qApp - > translate ( " MP3Exporter " , " MuseScore does not export MP3 files directly, but instead uses "
" the freely available LAME library. You must obtain %1 "
" separately (for details check the handbook), and then locate the file for MuseScore. \n "
2012-05-26 14:49:10 +02:00
" You only need to do this once. \n \n "
" Would you like to locate %2 now? " ) . arg ( getLibraryName ( ) ) . arg ( getLibraryName ( ) ) ,
QMessageBox : : Yes | QMessageBox : : No , QMessageBox : : NoButton ) ;
2017-03-20 15:53:06 +01:00
if ( ret = = QMessageBox : : Yes & & findLibrary ( ) ) {
2012-05-26 14:49:10 +02:00
mLibraryLoaded = initLibrary ( mLibPath ) ;
}
}
// Oh well, just give up
if ( ! validLibraryLoaded ( ) ) {
2014-03-25 13:33:47 +01:00
qDebug ( " Failed to locate LAME library " ) ;
2012-05-26 14:49:10 +02:00
return false ;
}
2014-03-25 13:33:47 +01:00
qDebug ( " LAME library successfully loaded " ) ;
2012-05-26 14:49:10 +02:00
return true ;
}
bool MP3Exporter : : validLibraryLoaded ( )
{
return mLibraryLoaded ;
}
void MP3Exporter : : setMode ( int mode )
{
mMode = mode ;
}
void MP3Exporter : : setBitrate ( int rate )
{
mBitrate = rate ;
}
void MP3Exporter : : setQuality ( int q , int r )
{
mQuality = q ;
mRoutine = r ;
}
void MP3Exporter : : setChannel ( int mode )
{
mChannel = mode ;
}
//---------------------------------------------------------
// initLibrary
//---------------------------------------------------------
bool MP3Exporter : : initLibrary ( QString libpath )
{
2014-03-25 13:33:47 +01:00
qDebug ( " Loading LAME from %s " , qPrintable ( libpath ) ) ;
2012-05-26 14:49:10 +02:00
lame_lib = new QLibrary ( libpath , 0 ) ;
if ( ! lame_lib - > load ( ) ) {
2014-03-25 13:33:47 +01:00
qDebug ( " load failed <%s> " , qPrintable ( lame_lib - > errorString ( ) ) ) ;
2012-05-26 14:49:10 +02:00
return false ;
}
2014-03-25 13:33:47 +01:00
/*qDebug("Actual LAME path %s",
2012-05-26 14:49:10 +02:00
FileNames : : PathFromAddr ( lame_lib - > resolve ( " lame_init " ) ) ) ; */
lame_init = ( lame_init_t * )
lame_lib - > resolve ( " lame_init " ) ;
get_lame_version = ( get_lame_version_t * )
lame_lib - > resolve ( " get_lame_version " ) ;
lame_init_params = ( lame_init_params_t * )
lame_lib - > resolve ( " lame_init_params " ) ;
lame_encode_buffer_float = ( lame_encode_buffer_float_t * )
lame_lib - > resolve ( " lame_encode_buffer_float " ) ;
lame_encode_flush = ( lame_encode_flush_t * )
lame_lib - > resolve ( " lame_encode_flush " ) ;
lame_close = ( lame_close_t * )
lame_lib - > resolve ( " lame_close " ) ;
lame_set_in_samplerate = ( lame_set_in_samplerate_t * )
lame_lib - > resolve ( " lame_set_in_samplerate " ) ;
lame_set_out_samplerate = ( lame_set_out_samplerate_t * )
lame_lib - > resolve ( " lame_set_out_samplerate " ) ;
lame_set_num_channels = ( lame_set_num_channels_t * )
lame_lib - > resolve ( " lame_set_num_channels " ) ;
lame_set_quality = ( lame_set_quality_t * )
lame_lib - > resolve ( " lame_set_quality " ) ;
lame_set_brate = ( lame_set_brate_t * )
lame_lib - > resolve ( " lame_set_brate " ) ;
lame_set_VBR = ( lame_set_VBR_t * )
lame_lib - > resolve ( " lame_set_VBR " ) ;
lame_set_VBR_q = ( lame_set_VBR_q_t * )
lame_lib - > resolve ( " lame_set_VBR_q " ) ;
lame_set_VBR_min_bitrate_kbps = ( lame_set_VBR_min_bitrate_kbps_t * )
lame_lib - > resolve ( " lame_set_VBR_min_bitrate_kbps " ) ;
lame_set_mode = ( lame_set_mode_t * )
lame_lib - > resolve ( " lame_set_mode " ) ;
lame_set_preset = ( lame_set_preset_t * )
lame_lib - > resolve ( " lame_set_preset " ) ;
lame_set_error_protection = ( lame_set_error_protection_t * )
lame_lib - > resolve ( " lame_set_error_protection " ) ;
lame_set_disable_reservoir = ( lame_set_disable_reservoir_t * )
lame_lib - > resolve ( " lame_set_disable_reservoir " ) ;
lame_set_padding_type = ( lame_set_padding_type_t * )
lame_lib - > resolve ( " lame_set_padding_type " ) ;
lame_set_bWriteVbrTag = ( lame_set_bWriteVbrTag_t * )
lame_lib - > resolve ( " lame_set_bWriteVbrTag " ) ;
// These are optional
lame_get_lametag_frame = ( lame_get_lametag_frame_t * )
lame_lib - > resolve ( " lame_get_lametag_frame " ) ;
lame_mp3_tags_fid = ( lame_mp3_tags_fid_t * )
lame_lib - > resolve ( " lame_mp3_tags_fid " ) ;
2013-05-17 18:02:34 +02:00
# if defined(Q_OS_WIN)
2012-05-26 14:49:10 +02:00
beWriteInfoTag = ( beWriteInfoTag_t * )
lame_lib - > resolve ( " beWriteInfoTag " ) ;
beVersion = ( beVersion_t * )
lame_lib - > resolve ( " beVersion " ) ;
# endif
if ( ! lame_init | |
! get_lame_version | |
! lame_init_params | |
! lame_encode_buffer_float | |
! lame_encode_flush | |
! lame_close | |
! lame_set_in_samplerate | |
! lame_set_out_samplerate | |
! lame_set_num_channels | |
! lame_set_quality | |
! lame_set_brate | |
! lame_set_VBR | |
! lame_set_VBR_q | |
! lame_set_mode | |
! lame_set_preset | |
! lame_set_error_protection | |
! lame_set_disable_reservoir | |
! lame_set_padding_type | |
! lame_set_bWriteVbrTag ) {
2014-03-25 13:33:47 +01:00
qDebug ( " Failed to find a required symbol in the LAME library " ) ;
2013-05-17 18:02:34 +02:00
# if defined(Q_OS_WIN)
2012-05-26 14:49:10 +02:00
if ( beVersion ) {
be_version v ;
beVersion ( & v ) ;
2013-05-17 15:30:03 +02:00
mBladeVersion = QString ( " You are linking to lame_enc.dll v%d.%d. This version is not compatible with MuseScore %d. \n Please download the latest version of the LAME MP3 library. " )
2012-05-26 14:49:10 +02:00
. arg ( v . byMajorVersion )
. arg ( v . byMinorVersion )
. arg ( 1 ) ; //TODO
}
# endif
lame_lib - > unload ( ) ;
delete lame_lib ;
return false ;
}
mGF = lame_init ( ) ;
if ( mGF = = NULL ) {
2014-03-27 17:14:56 +01:00
lame_lib - > unload ( ) ;
delete lame_lib ;
2012-05-26 14:49:10 +02:00
return false ;
}
return true ;
}
//---------------------------------------------------------
// freeLibrary
//---------------------------------------------------------
void MP3Exporter : : freeLibrary ( )
{
if ( mGF ) {
lame_close ( mGF ) ;
mGF = NULL ;
2014-03-27 17:14:56 +01:00
lame_lib - > unload ( ) ;
delete lame_lib ;
2012-05-26 14:49:10 +02:00
}
return ;
}
//---------------------------------------------------------
// getLibraryVersion
//---------------------------------------------------------
QString MP3Exporter : : getLibraryVersion ( )
{
if ( ! mLibraryLoaded )
return QString ( " " ) ;
return QString ( " LAME %s " ) . arg ( get_lame_version ( ) ) ;
}
//---------------------------------------------------------
// initializeStream
//---------------------------------------------------------
int MP3Exporter : : initializeStream ( int channels , int sampleRate )
{
if ( ! mLibraryLoaded )
return - 1 ;
if ( channels > 2 )
return - 1 ;
lame_set_error_protection ( mGF , false ) ;
lame_set_num_channels ( mGF , channels ) ;
lame_set_in_samplerate ( mGF , sampleRate ) ;
lame_set_out_samplerate ( mGF , sampleRate ) ;
lame_set_disable_reservoir ( mGF , true ) ;
lame_set_padding_type ( mGF , PAD_NO ) ;
// Add the VbrTag for all types. For ABR/VBR, a Xing tag will be created.
// For CBR, it will be a Lame Info tag.
lame_set_bWriteVbrTag ( mGF , true ) ;
// Set the VBR quality or ABR/CBR bitrate
switch ( mMode ) {
case MODE_SET :
{
int preset ;
if ( mQuality = = PRESET_INSANE )
preset = INSANE ;
else if ( mRoutine = = ROUTINE_FAST ) {
if ( mQuality = = PRESET_EXTREME )
preset = EXTREME_FAST ;
else if ( mQuality = = PRESET_STANDARD )
preset = STANDARD_FAST ;
else
preset = 1007 ; // Not defined until 3.96
}
else {
if ( mQuality = = PRESET_EXTREME )
preset = EXTREME ;
else if ( mQuality = = PRESET_STANDARD )
preset = STANDARD ;
else
preset = 1006 ; // Not defined until 3.96
}
lame_set_preset ( mGF , preset ) ;
}
break ;
case MODE_VBR :
lame_set_VBR ( mGF , ( mRoutine = = ROUTINE_STANDARD ? vbr_rh : vbr_mtrh ) ) ;
lame_set_VBR_q ( mGF , mQuality ) ;
break ;
case MODE_ABR :
lame_set_preset ( mGF , mBitrate ) ;
break ;
default :
lame_set_VBR ( mGF , vbr_off ) ;
lame_set_brate ( mGF , mBitrate ) ;
break ;
}
// Set the channel mode
MPEG_mode mode ;
if ( channels = = 1 )
mode = MONO ;
else if ( mChannel = = CHANNEL_JOINT )
mode = JOINT_STEREO ;
else
mode = STEREO ;
lame_set_mode ( mGF , mode ) ;
int rc = lame_init_params ( mGF ) ;
if ( rc < 0 )
return rc ;
#if 0
dump_config ( mGF ) ;
# endif
mInfoTagLen = 0 ;
mEncoding = true ;
return mSamplesPerChunk ;
}
//---------------------------------------------------------
// getOutBufferSize
//---------------------------------------------------------
int MP3Exporter : : getOutBufferSize ( )
{
if ( ! mEncoding )
return - 1 ;
return mOutBufferSize ;
}
//---------------------------------------------------------
// bufferPreamp
//---------------------------------------------------------
void MP3Exporter : : bufferPreamp ( float buffer [ ] , int nSamples )
{
for ( int i = 0 ; i < nSamples ; i + + )
buffer [ i ] = buffer [ i ] * 32768 ;
}
//---------------------------------------------------------
// encodeBuffer
//---------------------------------------------------------
int MP3Exporter : : encodeBuffer ( float inbufferL [ ] , float inbufferR [ ] , unsigned char outbuffer [ ] )
{
if ( ! mEncoding )
return - 1 ;
bufferPreamp ( inbufferL , mSamplesPerChunk ) ;
bufferPreamp ( inbufferR , mSamplesPerChunk ) ;
return lame_encode_buffer_float ( mGF , inbufferL , inbufferR , mSamplesPerChunk ,
outbuffer , mOutBufferSize ) ;
}
//---------------------------------------------------------
// encodeRemainder
//---------------------------------------------------------
int MP3Exporter : : encodeRemainder ( float inbufferL [ ] , float inbufferR [ ] , int nSamples ,
unsigned char outbuffer [ ] )
{
if ( ! mEncoding )
return - 1 ;
bufferPreamp ( inbufferL , nSamples ) ;
bufferPreamp ( inbufferR , nSamples ) ;
return lame_encode_buffer_float ( mGF , inbufferL , inbufferR , nSamples , outbuffer ,
mOutBufferSize ) ;
}
//---------------------------------------------------------
// encodeBufferMono
//---------------------------------------------------------
int MP3Exporter : : encodeBufferMono ( float inbuffer [ ] , unsigned char outbuffer [ ] )
{
if ( ! mEncoding )
return - 1 ;
bufferPreamp ( inbuffer , mSamplesPerChunk ) ;
return lame_encode_buffer_float ( mGF , inbuffer , inbuffer , mSamplesPerChunk ,
outbuffer , mOutBufferSize ) ;
}
//---------------------------------------------------------
// encodeRemainderMono
//---------------------------------------------------------
int MP3Exporter : : encodeRemainderMono ( float inbuffer [ ] , int nSamples ,
unsigned char outbuffer [ ] )
{
if ( ! mEncoding )
return - 1 ;
bufferPreamp ( inbuffer , nSamples ) ;
return lame_encode_buffer_float ( mGF , inbuffer , inbuffer , nSamples , outbuffer ,
mOutBufferSize ) ;
}
//---------------------------------------------------------
// finishStream
//---------------------------------------------------------
int MP3Exporter : : finishStream ( unsigned char outbuffer [ ] )
{
if ( ! mEncoding )
return - 1 ;
mEncoding = false ;
int result = lame_encode_flush ( mGF , outbuffer , mOutBufferSize ) ;
if ( lame_get_lametag_frame )
mInfoTagLen = lame_get_lametag_frame ( mGF , mInfoTagBuf , sizeof ( mInfoTagBuf ) ) ;
return result ;
}
//---------------------------------------------------------
// cancelEncoding
//---------------------------------------------------------
void MP3Exporter : : cancelEncoding ( )
{
mEncoding = false ;
}
/*void MP3Exporter::PutInfoTag(QFile f, qint64 off)
{
QDataStream out ( & f ) ;
if ( mGF ) {
if ( mInfoTagLen > 0 ) {
out . skipRawData ( off ) ;
out . writeRawData ( mInfoTagBuf , mInfoTagLen ) ;
}
2013-05-17 18:02:34 +02:00
# if defined(Q_OS_WIN)
2012-05-26 14:49:10 +02:00
else if ( beWriteInfoTag ) {
f . flush ( ) ;
QFileInfo fi ( f ) ;
2015-12-16 10:24:34 +01:00
beWriteInfoTag ( mGF , qPrintable ( fi . completeBaseName ( ) ) ) ;
2012-05-26 14:49:10 +02:00
mGF = NULL ;
}
# endif
else if ( lame_mp3_tags_fid ) {
std : : FILE * fp ;
if ( ( fp = std : : fdopen ( file . handle ( ) , " w+ " ) ) ! = NULL )
lame_mp3_tags_fid ( mGF , fp ) ;
}
}
f . seek ( f . size ( ) ) ;
} */
2013-05-17 18:02:34 +02:00
# if defined(Q_OS_WIN)
2012-05-26 14:49:10 +02:00
/* values for Windows */
QString MP3Exporter : : getLibraryPath ( )
{
QSettings settings ( " HKEY_LOCAL_MACHINE \\ Software \\ Lame for Audacity " , QSettings : : NativeFormat ) ;
QString sReturnedValue = settings . value ( " InstallPath " , " " ) . toString ( ) ;
if ( ! sReturnedValue . isEmpty ( ) ) {
return sReturnedValue ;
}
return QDir : : rootPath ( ) ;
}
QString MP3Exporter : : getLibraryName ( )
{
return QString ( " lame_enc.dll " ) ;
}
QString MP3Exporter : : getLibraryTypeString ( )
{
return QString ( " Only lame_enc.dll (lame_enc.dll) ; ; Dynamically Linked Libraries ( * . dll ) ; ; All Files ( * . * ) " ) ;
}
2013-05-16 16:12:22 +02:00
# elif defined(Q_OS_MAC)
2012-05-26 14:49:10 +02:00
/* values for Mac OS X */
QString MP3Exporter : : getLibraryPath ( )
{
return QString ( " /usr/local/lib/audacity " ) ;
}
QString MP3Exporter : : getLibraryName ( )
{
return QString ( " libmp3lame.dylib " ) ;
}
QString MP3Exporter : : getLibraryTypeString ( )
{
return QString ( " Only libmp3lame.dylib (libmp3lame.dylib) ; ; Dynamic Libraries ( * . dylib ) ; ; All Files ( * ) " ) ;
}
2013-05-16 16:12:22 +02:00
# else //!Q_OS_MAC
2012-05-26 14:49:10 +02:00
/* Values for Linux / Unix systems */
QString MP3Exporter : : getLibraryPath ( )
{
return QString ( " /usr/lib " ) ;
}
QString MP3Exporter : : getLibraryName ( )
{
return QString ( " libmp3lame.so.0 " ) ;
}
QString MP3Exporter : : getLibraryTypeString ( )
{
return QString ( " Only libmp3lame.so.0 (libmp3lame.so.0) ; ; Primary Shared Object files ( * . so ) ; ; Extended Libraries ( * . so * ) ; ; All Files ( * ) " ) ;
}
# endif //mac
2013-05-13 18:49:17 +02:00
}
2012-05-26 14:49:10 +02:00