> I think Sean commited most of the patches, though I still have some
> changes in my working copy, mostly involving metadata updating. I'll
> send those to you later today.

Here's another patch. This one includes:

  * SConscript code to optionally compile with shoutcast support for
OGG and/or MP3 (needs at least one)
  * Update metadata for shoutcast servers
  * Improved metadata selection code

The only thing missing, I think, is to add a little leeway with the
crossfader metadata selection code, since some MIDI controllers, like
my M-Audio X-Session, don't have a slot or nitch at 0. This could
easily lead to false positives. It also might be useful to add a
little more inteligence to this code to detect if people are merely
scratching with a certain track.

-- 
-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GCS d- s+:- a-- C+++(++++)$ UL+++$ P+ L+++>++++ E W++ N o?
K- w++(---) O? M-- V PS+++ PE-(--) Y+(++) PGP t(+) 5(+) X++
R b+>++ DI+ D+ G e h-(--) r y+
------END GEEK CODE BLOCK------
=== modified file 'mixxx/src/SConscript'
--- mixxx/src/SConscript	2009-05-15 03:08:59 +0000
+++ mixxx/src/SConscript	2009-05-22 15:53:18 +0000
@@ -211,6 +211,8 @@
 opts.Add('ffmpeg', '(EXPERIMENTAL) Set to 1 to enable FFMPEG support', 0)
 opts.Add('vinylcontrol', 'Set to 1 to enable vinyl control support', 1)
 opts.Add('shoutcast', 'Set to 1 to enable shoutcast support', 0)
+opts.Add('shoutcastlame', 'Set to 1 to enable mp3 support in shoutcast using libmp3lame', 0)
+opts.Add('shoutcastvorbis', 'Set to 1 to enable ogg vorbis support in shoutcast using libvorbisenc', 0)
 opts.Add('msvshacks', 'Set to 1 to build properly with MS Visual Studio 2005 (Express users should leave this off)', 0)
 opts.Add('cmetrics', 'Set to 1 to enable crash reporting/usage statistics via Case Metrics (This should be disabled on development builds)', 0)
 opts.Add('optimize', 'Set to 1 to enable -O3 compiler optimizations. Set to 2 to enable Pentium 4 optimizations. Set to 3 to enable Intel Core optimizations, and set to 4 to enable Intel Core 2 optimizations.', 1)
@@ -854,16 +856,40 @@
 
 #Experimental Shoutcast
 flags_shoutcast = getFlags(env, 'shoutcast', 0)
+flags_shoutcastlame = getFlags(env, 'shoutcastlame', 0)
+flags_shoutcastvorbis = getFlags(env, 'shoutcastvorbis', 0)
+
 if int(flags_shoutcast):
 #TODO: check for libshout
-	env.Append(LIBS = 'shout');
-	env.Append(LIBS = 'vorbisenc');
-	env.Append(LIBS = 'mp3lame');
-	env.Append(CPPDEFINES = '__SHOUTCAST__')
-	sources += Split(""" dlgprefshoutcast.cpp engine/engineshoutcast.cpp encoder.cpp encodervorbis.cpp encodermp3.cpp""" )
-	env.Uic4('dlgprefshoutcastdlg.ui')
-	print "Shoutcast support... enabled"
-	build_flags += 'shoutcast '
+	if int(flags_shoutcastlame) or int(flags_shoutcastvorbis):
+		env.Append(LIBS = 'shout');
+		env.Append(CPPDEFINES = '__SHOUTCAST__')
+		sources += Split(""" dlgprefshoutcast.cpp engine/engineshoutcast.cpp encoder.cpp """ )
+		build_flags += 'shoutcast '
+		
+		if int(flags_shoutcastlame):
+			env.Append(LIBS = 'mp3lame');
+			env.Append(CPPDEFINES = '__SHOUTCAST_LAME__')
+			sources += Split(""" encodermp3.cpp """)
+			build_flags += 'shoutcastlame '
+		
+		if int(flags_shoutcastvorbis):
+			env.Append(LIBS = 'vorbisenc');
+			env.Append(CPPDEFINES = '__SHOUTCAST_VORBIS__')
+			sources += Split("""  encodervorbis.cpp """)
+			build_flags += 'shoutcastvorbis '
+		
+		if int(flags_shoutcastlame) and int(flags_shoutcastvorbis):
+			print "Shoutcast support (OGG/MP3)... enabled"
+		elif int(flags_shoutcastlame):
+			print "Shoutcast support (MP3)... enabled"
+		else:
+			print "Shoutcast support (OGG)... enabled"
+		
+		env.Uic4('dlgprefshoutcastdlg.ui')
+	else:
+		print "Shoutcast support disabled... no supported encoders"
+	
 else:
 	print "Shoutcast support... disabled"
 

=== modified file 'mixxx/src/engine/engineshoutcast.cpp'
--- mixxx/src/engine/engineshoutcast.cpp	2009-02-18 06:27:27 +0000
+++ mixxx/src/engine/engineshoutcast.cpp	2009-05-22 15:20:36 +0000
@@ -19,8 +19,13 @@
 #include "configobject.h"
 #include "dlgprefshoutcast.h"
 
+#ifdef __SHOUTCAST_VORBIS__
 #include "encodervorbis.h"
+#endif // __SHOUTCAST_VORBIS__
+#ifdef __SHOUTCAST_LAME__
 #include "encodermp3.h"
+#endif // __SHOUTCAST_LAME__
+
 #include "playerinfo.h"
 #include "trackinfoobject.h"
 
@@ -58,6 +63,15 @@
         return;
     }
     
+    if (!(m_pShoutMetaData = shout_metadata_new())) {
+        qDebug() << "Cound not allocate shout_metadata_t";
+        return;
+    }
+    
+    // set to a high number to automatically update the metadata
+    // on the first change
+    m_pMetaDataLife = 31337;
+    
     //Initialize the m_pShout structure with the info from Mixxx's shoutcast preferences.
     updateFromPreferences();
 
@@ -75,10 +89,20 @@
     
     // Initialize encoder
     if ( ! qstrcmp(baFormat, "MP3")) {
+#ifdef __SHOUTCAST_LAME__
         encoder = new EncoderMp3(m_pConfig, this);
+#else
+        qDebug() << "*** Missing MP3 Encoder Support";
+        return;
+#endif // __SHOUTCAST_LAME__
     }
     else if ( ! qstrcmp(baFormat, "Ogg Vorbis")) {
+#ifdef __SHOUTCAST_VORBIS__
         encoder = new EncoderVorbis(m_pConfig, this);
+#else
+        qDebug() << "*** Missing OGG Vorbis Encoder Support";
+        return;
+#endif // __SHOUTCAST_VORBIS__
     }
     else {
         qDebug() << "**** Unknown Encoder Format";
@@ -96,6 +120,8 @@
     delete encoder;
     delete m_pUpdateShoutcastFromPrefs;
     
+    if (m_pShoutMetaData)
+        shout_metadata_free(m_pShoutMetaData);
     if (m_pShout)
         shout_close(m_pShout);
     shout_shutdown();
@@ -259,15 +285,130 @@
     }
 }
 
-/*void EngineShoutcast::wrapper2writePage(void *pObj, unsigned char *header, unsigned char *body,
-                                        int headerLen, int bodyLen)
-{
-    EngineShoutcast* mySelf = (EngineShoutcast*)pObj;
-    pObj->writePage(header, body, headerLen, bodyLen);
-}*/
-
-void EngineShoutcast::process(const CSAMPLE *pIn, const CSAMPLE *pOut, const int iBufferSize)
-{
-//    encoder->encodeBuffer((void*) &objA, EngineShoutcast::wrapper2writePage, pOut, iBufferSize);
+void EngineShoutcast::process(const CSAMPLE *, const CSAMPLE *pOut, const int iBufferSize)
+{
     if (iBufferSize > 0) encoder->encodeBuffer(pOut, iBufferSize);
+    
+    if ( metaDataHasChanged())
+        updateMetaData();
+}
+
+/* Algorithm which simply flips the lowest and/or second lowest bits,
+ * bits 1 and 2, to represent which track is active and returns the result.
+ */
+
+int EngineShoutcast::getActiveTracks()
+{
+    int tracks = 0;
+    
+    
+    if (ControlObject::getControl(ConfigKey("[Channel1]","play"))->get()==1.) tracks |= 1;
+    if (ControlObject::getControl(ConfigKey("[Channel2]","play"))->get()==1.) tracks |= 2;
+    
+    if (tracks ==  0)
+        return 0;
+    
+	// Detect the dominant track by checking the crossfader and volume levels
+    if ((tracks & 1) && (tracks && 2)) {
+		ControlObjectThreadMain* pCrossfader = new ControlObjectThreadMain(
+													 ControlObject::getControl(ConfigKey(
+													 "[Master]","crossfader")));
+		
+		// allow a bit of leeway with the crossfader
+		if ( pCrossfader->get() < 0.0001 ) {
+			tracks = 1;
+		}
+		else if ( pCrossfader->get() > 0.0001 ) {
+			tracks = 2;
+		}
+		else {
+			ControlObjectThreadMain* pVolume1 = new ControlObjectThreadMain(
+													 ControlObject::getControl(ConfigKey(
+													 "[Channel1]","volume")));
+			
+			ControlObjectThreadMain* pVolume2 = new ControlObjectThreadMain(
+													 ControlObject::getControl(ConfigKey(
+													 "[Channel2]","volume")));
+			
+			if (pVolume1->get() > pVolume2->get()) {
+				tracks = 1;
+			}
+			else if (pVolume1->get() < pVolume2->get()) {
+				tracks = 2;
+			}
+			
+			delete pVolume1;
+			delete pVolume2;
+		}	
+		
+		delete pCrossfader;
+		
+    }
+    
+    return tracks;
+}
+
+bool EngineShoutcast::metaDataHasChanged()
+{
+    int tracks;
+    TrackInfoObject *newMetaData;
+    bool changed = false;
+    
+    
+    if ( m_pMetaDataLife < 32 ) {
+        m_pMetaDataLife++;
+        return false;
+    }
+    
+    m_pMetaDataLife = 0;
+    
+    
+    tracks = getActiveTracks();
+    
+    
+    switch (tracks)
+    {
+    case 0:
+        // no tracks are playing
+        // we should set the metadata to nothing
+        break;
+    case 1:
+        // track 1 is active
+        
+        newMetaData = PlayerInfo::Instance().getTrackInfo(1);
+        if (newMetaData != m_pMetaData)
+        {
+            m_pMetaData = newMetaData;
+            changed = true;
+        }
+        break;
+    case 2:
+        // track 2 is active
+        newMetaData = PlayerInfo::Instance().getTrackInfo(2);
+        if (newMetaData != m_pMetaData)
+        {
+            m_pMetaData = newMetaData;
+            changed = true;
+        }
+        break;
+    case 3:
+        // both tracks are active, just stick with it for now
+        break;
+    }
+    
+    qDebug() << "tracks = " << tracks << " changed = " << changed;
+    
+    
+    return changed;
+}
+
+void EngineShoutcast::updateMetaData()
+{
+    // convert QStrings to char*s
+    QByteArray baArtist = m_pMetaData->getArtist().toLatin1();
+    QByteArray baTitle = m_pMetaData->getTitle().toLatin1();
+    QByteArray baSong = baArtist + " - " + baTitle;
+    
+    shout_metadata_add(m_pShoutMetaData, "song",  baSong.data());
+    shout_set_metadata(m_pShout, m_pShoutMetaData);
 }

=== modified file 'mixxx/src/engine/engineshoutcast.h'
--- mixxx/src/engine/engineshoutcast.h	2009-02-18 04:28:21 +0000
+++ mixxx/src/engine/engineshoutcast.h	2009-04-08 11:59:16 +0000
@@ -52,7 +52,13 @@
 //                   int headerLen, int bodyLen, int count);
 private:
     void serverConnect();
+    int getActiveTracks();
+    bool metaDataHasChanged();
+    void updateMetaData();
+    TrackInfoObject *m_pMetaData;
     shout_t *m_pShout;
+    shout_metadata_t *m_pShoutMetaData;
+    int m_pMetaDataLife;
     long m_iShoutStatus;
     ConfigObject<ConfigValue> *m_pConfig;
     ControlObject* recReady;

------------------------------------------------------------------------------
Register Now for Creativity and Technology (CaT), June 3rd, NYC. CaT
is a gathering of tech-side developers & brand creativity professionals. Meet
the minds behind Google Creative Lab, Visual Complexity, Processing, & 
iPhoneDevCamp asthey present alongside digital heavyweights like Barbarian
Group, R/GA, & Big Spaceship. http://www.creativitycat.com 
_______________________________________________
Mixxx-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mixxx-devel

Reply via email to