diff --git a/CMakeLists.txt b/CMakeLists.txt index d71e0c347..12a693367 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -267,6 +267,7 @@ find_package( Cdparanoia ) if (CDPARANOIA_FOUND) find_package( CDDB ) find_package( MusicBrainz5 ) + find_package( Lame ) endif (CDPARANOIA_FOUND) if (ENABLE_TAGLIB) @@ -622,6 +623,10 @@ if (NOT WIN32) TARGET_LINK_LIBRARIES(cantata ${MUSICBRAINZ5_LIBRARIES}) include_directories(${MUSICBRAINZ5_INCLUDE_DIR}) endif (MUSICBRAINZ5_FOUND) + if (LAME_FOUND) + TARGET_LINK_LIBRARIES(cantata ${LAME_LIBS}) + include_directories(${LAME_INCLUDE_DIR}) + endif (LAME_FOUND) endif (CDDB_FOUND OR MUSICBRAINZ5_FOUND) endif (NOT WIN32) diff --git a/README b/README index 2797b66c2..3233da3df 100644 --- a/README +++ b/README @@ -18,15 +18,19 @@ Cantata requires the following Qt libraries: Cantata may also use the following optional libraries: -1. KDElibs4 -2. QtWebKit - used for the artist/album information page. If QtWebKit is not - found, the page will not be built. -3. TagLib - used for the tag edit dialog, replaygain, track organizer, and - for UMS device support. -4. LibMTP - used to support MTP devices. -5. FFMPEG (libavcodec) - used by ReplayGain detection code. -6. SpeexDSP - used by ReplayGain detection code. -7. MPG123 - used by ReplayGain detection code. + 1. KDElibs4 + 2. QtWebKit - used for the artist/album information page. If QtWebKit is not + found, the page will not be built. + 3. TagLib - used for the tag edit dialog, replaygain, track organizer, and + for UMS device support. + 4. LibMTP - used to support MTP devices. + 5. FFMPEG (libavcodec) - used by ReplayGain detection code. + 6. SpeexDSP - used by ReplayGain detection code. + 7. MPG123 - used by ReplayGain detection code. + 8. CDParanoia - required to read Audio CDs. + 9. CDDB - either this or MusicBrainz5 required for Audio CDs +10. MusicBrainz5 - either this or CDDB required for Audio CDs +11. Lame - used to encode Audio CD streams when sent via HTTP server. Translations diff --git a/cmake/FindLame.cmake b/cmake/FindLame.cmake new file mode 100644 index 000000000..3ddc752d0 --- /dev/null +++ b/cmake/FindLame.cmake @@ -0,0 +1,14 @@ +# - Try to find LAME +# Once done this will define +# +# LAME_FOUND - system has UDev +# LAME_INCLUDE_DIR - the libudev include directory +# LAME_LIBS - The libudev libraries + +find_path(LAME_INCLUDE_DIR lame/lame.h) +find_library(LAME_LIBS mp3lame) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LAME DEFAULT_MSG LAME_INCLUDE_DIR LAME_LIBS) + +mark_as_advanced(LAME_INCLUDE_DIR LAME_LIBS) diff --git a/config.h.cmake b/config.h.cmake index 67d68afde..973103e17 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -25,6 +25,7 @@ #cmakedefine PHONON_FOUND 1 #cmakedefine FFMPEG_FOUND 1 #cmakedefine MPG123_FOUND 1 +#cmakedefine LAME_FOUND 1 #cmakedefine CDDB_FOUND 1 #cmakedefine MUSICBRAINZ5_FOUND 1 #cmakedefine USE_SPEEX_RESAMPLER 1 diff --git a/devices/audiocdsettings.cpp b/devices/audiocdsettings.cpp index 46815cc39..b55adc1fd 100644 --- a/devices/audiocdsettings.cpp +++ b/devices/audiocdsettings.cpp @@ -41,6 +41,16 @@ AudioCdSettings::AudioCdSettings(QWidget *p) REMOVE(cdLookup) REMOVE(cdLookupLabel) #endif + + #if !defined CDDB_FOUND + REMOVE(cddbHost) + REMOVE(cddbHostLabel) + REMOVE(cddbPort) + REMOVE(cddbPortLabel) + #endif + #if !defined CDDB_FOUND + REMOVE(playbackOptions) + #endif } void AudioCdSettings::load() @@ -49,11 +59,9 @@ void AudioCdSettings::load() #if defined CDDB_FOUND cddbHost->setText(Settings::self()->cddbHost()); cddbPort->setValue(Settings::self()->cddbPort()); - #else - REMOVE(cddbHost) - REMOVE(cddbHostLabel) - REMOVE(cddbPort) - REMOVE(cddbPortLabel) + #endif + #if defined CDDB_FOUND + cdMp3->setChecked(Settings::self()->cdMp3()); #endif paranoiaFull->setChecked(Settings::self()->paranoiaFull()); paranoiaNeverSkip->setChecked(Settings::self()->paranoiaNeverSkip()); @@ -79,5 +87,7 @@ void AudioCdSettings::save() #if defined CDDB_FOUND && defined MUSICBRAINZ5_FOUND Settings::self()->saveUseCddb(cdLookup->itemData(cdLookup->currentIndex()).toBool()); #endif + #if defined CDDB_FOUND + Settings::self()->saveCdMp3(cdMp3->isChecked()); + #endif } - diff --git a/devices/audiocdsettings.ui b/devices/audiocdsettings.ui index 047b22517..3ec7a09ad 100644 --- a/devices/audiocdsettings.ui +++ b/devices/audiocdsettings.ui @@ -6,8 +6,8 @@ 0 0 - 394 - 217 + 506 + 462 @@ -92,7 +92,7 @@ - + Full paranoia mode (best quality): @@ -105,7 +105,7 @@ - + Never skip on read error: @@ -120,6 +120,59 @@ + + + + Playback + + + + + + Encode tracks to MP3: + + + cdMp3 + + + + + + + + + + <i> +<b>NOTE:</b> To enable playback of Audio CDs, you <b>must</b> enable Cantata's HTTP server. +<br/> +<br/> +<b>NOTE:</b> Some MPD installations cannot playback raw CD Audio via HTTP streams. To work around this, you can elect to have Cantata convert the CD Audio to MP3 on-the-fly when MPD reads the HTTP stream. +</i> + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 1 + 8 + + + + + + + diff --git a/gui/settings.cpp b/gui/settings.cpp index 1e929e0cb..8e8c1cdf8 100644 --- a/gui/settings.cpp +++ b/gui/settings.cpp @@ -582,6 +582,12 @@ bool Settings::cdAuto() { return GET_BOOL("cdAuto", true); } +#ifdef LAME_FOUND +bool Settings::cdMp3() +{ + return GET_BOOL("cdMp3", true); +} +#endif #endif #if defined CDDB_FOUND && defined MUSICBRAINZ5_FOUND @@ -953,6 +959,12 @@ void Settings::saveCdAuto(bool v) { SET_VALUE_MOD(cdAuto) } +#ifdef LAME_FOUND +void Settings::saveCdMp3(bool v) +{ + SET_VALUE_MOD(cdMp3) +} +#endif #endif #if defined CDDB_FOUND && defined MUSICBRAINZ5_FOUND diff --git a/gui/settings.h b/gui/settings.h index b33eb84e2..bf2171532 100644 --- a/gui/settings.h +++ b/gui/settings.h @@ -153,6 +153,9 @@ public: #endif #if defined CDDB_FOUND || defined MUSICBRAINZ5_FOUND bool cdAuto(); + #ifdef LAME_FOUND + bool cdMp3(); + #endif #endif #if defined CDDB_FOUND && defined MUSICBRAINZ5_FOUND bool useCddb(); @@ -227,6 +230,9 @@ public: #endif #if defined CDDB_FOUND || defined MUSICBRAINZ5_FOUND void saveCdAuto(bool v); + #ifdef LAME_FOUND + void saveCdMp3(bool v); + #endif #endif #if defined CDDB_FOUND && defined MUSICBRAINZ5_FOUND void saveUseCddb(bool v); diff --git a/http/httpsocket.cpp b/http/httpsocket.cpp index c0f7433fc..270dfadb0 100644 --- a/http/httpsocket.cpp +++ b/http/httpsocket.cpp @@ -28,6 +28,9 @@ #if defined CDDB_FOUND || defined MUSICBRAINZ5_FOUND #include "cdparanoia.h" #include "extractjob.h" +#ifdef LAME_FOUND +#include "lame/lame.h" +#endif #endif #include #include @@ -243,7 +246,7 @@ QList split(const QByteArray &a) } return rv; } - +#include void HttpSocket::readClient() { if (terminated) { @@ -278,8 +281,32 @@ void HttpSocket::readClient() int count = 0; cdparanoia.seek(firstSector, SEEK_SET); ok=true; - writeMimeType(QLatin1String("audio/x-wav"), socket); - ExtractJob::writeWavHeader(*socket); + #ifdef LAME_FOUND + lame_global_flags *lame=0; + static const int constMp3BufferSize=CD_FRAMESIZE_RAW*2*sizeof(short int); + static const int constPcmSize=CD_FRAMESIZE_RAW/(2*sizeof(short int)); + unsigned char mp3Buffer[constMp3BufferSize]; + if (Settings::self()->cdMp3()) { + lame = lame_init(); + lame_set_num_channels(lame, 2); + lame_set_in_samplerate(lame, 44100); + lame_set_brate(lame, 128); + lame_set_quality(lame, 5); + lame_set_VBR(lame, vbr_off); + if (-1!=lame_init_params(lame)) { + writeMimeType(QLatin1String("audio/mpeg"), socket); + } else { + lame_close(lame); + lame=0; + } + } + if (!lame) { + #endif + writeMimeType(QLatin1String("audio/x-wav"), socket); + ExtractJob::writeWavHeader(*socket); + #ifdef LAME_FOUND + } + #endif bool stop=false; while (!terminated && (firstSector+count) <= lastSector && !stop) { qint16 *buf = cdparanoia.read(); @@ -288,17 +315,32 @@ void HttpSocket::readClient() } char *buffer=(char *)buf; qint64 writePos=0; + qint64 toWrite=CD_FRAMESIZE_RAW; + + #ifdef LAME_FOUND + if (lame) { + toWrite=lame_encode_buffer_interleaved(lame, (short *)buffer, constPcmSize, mp3Buffer, constMp3BufferSize); + buffer=(char *)mp3Buffer; + } + #endif + do { - qint64 bytesWritten = socket->write(&buffer[writePos], CD_FRAMESIZE_RAW - writePos); + qint64 bytesWritten=socket->write(&buffer[writePos], toWrite - writePos); if (terminated || -1==bytesWritten) { stop=true; break; } socket->flush(); writePos+=bytesWritten; - } while (!terminated && writePos