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