This is a rather large patch, since I include a Duck-Typing pattern to
call two different encoders from EngineShoutcast.

The basic ChangeLog is:

  * Encoder Class to implement the interface for EncoderVorbis and EncoderMp3
  * EncoderMp3 to encode to mp3 format using libmp3lame
  * Create three encoderInit methods:
       * default value (128 kbps)
       * float parameter for quality settings, ie: 0.4
       * integer parameter for managed mode or CBR bitrate
  * Add files encoder.cpp and encodermp3.cpp to SConscript to be built
when shoutcast is enabled
  * Add options to the dialogs to select Shoutcast as a server type,
several more bitrates and to select mp3 format

Yes... it's rather long but, in my defense it could be longer, since
I'm still missing metadata support in engineshoutcast itself (which
will allow metadata with the mp3 format). I also refrained from
generally cleaning up the code, wherever possible.

Hope the people can enjoy this. :)

-- 
-----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------
Index: src/encoder.cpp
===================================================================
--- src/encoder.cpp	(revision 0)
+++ src/encoder.cpp	(revision 0)
@@ -0,0 +1,37 @@
+/****************************************************************************
+                   encoder.cpp  - encoder API for mixxx
+                             -------------------
+    copyright            : (C) 2009 by Phillip Whelan
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#include <stdlib.h> // needed for random num gen
+#include <time.h> // needed for random num gen
+#include <string.h> // needed for memcpy
+#include <QDebug>
+
+#include "engine/engineabstractrecord.h"
+#include "controlobjectthreadmain.h"
+#include "controlobject.h"
+#include "playerinfo.h"
+#include "trackinfoobject.h"
+
+#include "encoder.h"
+
+// Constructor
+Encoder::Encoder()
+{
+}
+
+// Destructor
+Encoder::~Encoder()
+{
+}
Index: src/encoder.h
===================================================================
--- src/encoder.h	(revision 0)
+++ src/encoder.h	(revision 0)
@@ -0,0 +1,44 @@
+/****************************************************************************
+                   encoder.h  - encoder API for mixxx
+                             -------------------
+    copyright            : (C) 2009 by Phillip Whelan
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef ENCODER_H
+#define ENCODER_H
+
+#include <stdlib.h> // needed for random num gen
+#include <time.h> // needed for random num gen
+#include <string.h> // needed for memcpy
+#include <QDebug>
+
+#include "engine/engineabstractrecord.h"
+#include "controlobjectthreadmain.h"
+#include "controlobject.h"
+#include "playerinfo.h"
+#include "trackinfoobject.h"
+
+
+class Encoder : public QObject {
+    Q_OBJECT
+
+public:
+    Encoder();
+    ~Encoder();
+    virtual int initEncoder() = 0;
+    virtual int initEncoder(float quality) = 0;
+    virtual int initEncoder(int bitrate) = 0;
+    virtual void encodeBuffer(const CSAMPLE *samples, const int size) = 0;
+};
+
+#endif // ENCODER_H
+
Index: src/encodermp3.cpp
===================================================================
--- src/encodermp3.cpp	(revision 0)
+++ src/encodermp3.cpp	(revision 0)
@@ -0,0 +1,210 @@
+/****************************************************************************
+                   encodermp3.cpp  - mp3 encoder for mixxx
+                             -------------------
+    copyright            : (C) 2007 by Wesley Stessens
+                           (C) 2009 by Phillip Whelan (rewritten for mp3)
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+
+#include "encodermp3.h"
+
+#include <stdlib.h> // needed for random num     
+#include <time.h> // needed for random num     
+#include <string.h> // needed for memcpy
+#include <QDebug>
+
+#include "engine/engineabstractrecord.h"
+#include "controlobjectthreadmain.h"
+#include "controlobject.h"
+#include "playerinfo.h"
+#include "trackinfoobject.h"
+
+// Constructor
+EncoderMp3::EncoderMp3(ConfigObject<ConfigValue> *_config, EngineAbstractRecord *engine)
+{
+    if (engine) pEngine = engine;
+    metaDataTitle = metaDataArtist = "";
+    m_pConfig = _config;
+}
+
+// Destructor
+EncoderMp3::~EncoderMp3()
+{
+    flushStream();
+    lame_close(m_lameFlags);
+}
+
+/*
+ * Grow the outBuffer if needed.
+ */
+
+int EncoderMp3::bufferOutGrow(int size)
+{
+    if ( m_bufferOutSize >= size )
+        return 0;
+    
+    m_bufferOut = (unsigned char *)realloc(m_bufferOut, size);
+    if ( m_bufferOut == NULL )
+        return -1;
+    
+    m_bufferOutSize = size;
+    return 0;
+}
+
+/*
+ * Grow the inBuffer(s) if needed.
+ */
+
+int EncoderMp3::bufferInGrow(int size)
+{
+    if ( m_bufferInSize >= size )
+        return 0;
+    
+    m_bufferIn[0] = (float *)realloc(m_bufferIn[0], size * sizeof(float));
+    m_bufferIn[1] = (float *)realloc(m_bufferIn[1], size * sizeof(float));
+    if ((m_bufferIn[0] == NULL) || (m_bufferIn[1] == NULL))
+        return -1;
+    
+    m_bufferInSize = size;
+    return 0;
+}
+
+void EncoderMp3::flushStream()
+{
+    int rc;
+    
+    
+    rc = lame_encode_flush_nogap(m_lameFlags, m_bufferOut, m_bufferOutSize);
+    pEngine->writePage(NULL, m_bufferOut, 0, rc);
+}
+
+void EncoderMp3::encodeBuffer(const CSAMPLE *samples, const int size)
+{
+    int outsize;
+    int rc;
+    int i;
+    
+    
+    outsize = (int)((1.25 * size + 7200) + 1);
+    bufferOutGrow(outsize);
+    
+    bufferInGrow(size);
+    
+    // Deinterleave samples
+    for (i = 0; i < size/2; ++i)
+    {
+        m_bufferIn[0][i] = samples[i*2];
+        m_bufferIn[1][i] = samples[i*2+1];
+    }
+    
+    rc = lame_encode_buffer_float(m_lameFlags, m_bufferIn[0], m_bufferIn[1], 
+            size/2, m_bufferOut, m_bufferOutSize);
+    if ( rc < 0 )
+        return;
+    
+    pEngine->writePage(NULL, m_bufferOut, 0, rc);
+}
+
+void EncoderMp3::initStream()
+{
+    m_bufferOutSize = (int)((1.25 * 20000 + 7200) + 1);
+    m_bufferOut = (unsigned char *)malloc(m_bufferOutSize);
+    
+    m_bufferIn[0] = (float *)malloc(m_bufferOutSize * sizeof(float));
+    m_bufferIn[1] = (float *)malloc(m_bufferOutSize * sizeof(float));
+    
+    return;
+}
+
+int EncoderMp3::initEncoder(int bitrate)
+{
+    unsigned long samplerate = m_pConfig->getValueString(ConfigKey("[Soundcard]","Samplerate")).toULong();
+    
+    
+    m_lameFlags = lame_init();
+    if ( m_lameFlags == NULL ) {
+        qDebug() << "Unable to initialize MP3";
+        return -1;
+    }
+    
+    lame_set_num_channels(m_lameFlags, 2);
+    lame_set_in_samplerate(m_lameFlags, samplerate);
+    lame_set_out_samplerate(m_lameFlags, samplerate);
+    lame_set_brate(m_lameFlags, 128);
+    lame_set_mode(m_lameFlags, STEREO);
+    lame_set_quality(m_lameFlags, 2);
+    lame_set_bWriteVbrTag(m_lameFlags, 0);
+    
+    
+    if (( lame_init_params(m_lameFlags)) < 0) {
+        qDebug() << "Unable to initialize MP3 parameters";
+        return -1;
+    }
+    
+    initStream();
+    
+    return 0;
+}
+
+/*
+ * A loose conversion table so we can simulate the vorbis code.
+ *
+ * -q-1 48 kbit/s
+ * -q0     64 kbit/s
+ * -q1     80 kbit/s
+ * -q2     96 kbit/s
+ * -q3     112 kbit/s
+ * -q4     128 kbit/s
+ * -q5     160 kbit/s
+ * -q6     192 kbit/s
+ * -q7     224 kbit/s
+ * -q8     256 kbit/s
+ * -q9     320 kbit/s
+ * -q10 500 kbit/s
+ */
+
+int EncoderMp3::initEncoder(float quality)
+{
+    switch((int)(quality * 10)) {
+        case -1:
+            return this->initEncoder(48);
+        case 0:
+            return this->initEncoder(64);
+        case 1:
+            return this->initEncoder(80);
+        case 2:
+            return this->initEncoder(96);
+        case 3:
+            return this->initEncoder(112);
+        case 4:
+            return this->initEncoder(128);
+        case 5:
+            return this->initEncoder(160);
+        case 6:
+            return this->initEncoder(192);
+        case 7:
+            return this->initEncoder(224);
+        case 8:
+            return this->initEncoder(256);
+        case 9:
+            return this->initEncoder(320);
+        case 10:
+            return this->initEncoder(500);
+    }
+    
+    return -1;
+}
+
+int EncoderMp3::initEncoder()
+{
+    return this->initEncoder(128);
+}
Index: src/encodermp3.h
===================================================================
--- src/encodermp3.h	(revision 0)
+++ src/encodermp3.h	(revision 0)
@@ -0,0 +1,60 @@
+/****************************************************************************
+                   encodermp3.h  - mp3 encoder for mixxx
+                             -------------------
+    copyright            : (C) 2007 by Wesley Stessens
+                           (C) 2009 by Phillip Whelan (rewritten for mp3)
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef ENCODERMP3_H
+#define ENCODERMP3_H
+
+#include <QObject>
+#include "defs.h"
+#include "configobject.h"
+#include "encoder.h"
+
+#include <lame/lame.h> // may be elsewhere on other distros besides Ubuntu
+
+class EngineAbstractRecord;
+class TrackInfoObject;
+
+class EncoderMp3 : public Encoder {
+    Q_OBJECT
+
+public:
+    EncoderMp3(ConfigObject<ConfigValue> *_config, EngineAbstractRecord *engine=0);
+    ~EncoderMp3();
+    int initEncoder();
+    int initEncoder(float quality);
+    int initEncoder(int bitrate);
+    void encodeBuffer(const CSAMPLE *samples, const int size);
+
+private:
+    void flushStream();
+    void initStream();
+    int bufferOutGrow(int size);
+    int bufferInGrow(int size);
+
+    ConfigObject<ConfigValue> *m_pConfig; /* provides ConfigKey access */
+    lame_global_flags *m_lameFlags;
+    unsigned char *m_bufferOut;
+    int m_bufferOutSize;
+    float *m_bufferIn[2];
+    int m_bufferInSize;
+    
+    EngineAbstractRecord *pEngine;
+    TrackInfoObject *m_pMetaData;
+    char *metaDataTitle;
+    char *metaDataArtist;
+};
+
+#endif
Index: src/encodervorbis.cpp
===================================================================
--- src/encodervorbis.cpp	(revision 2643)
+++ src/encodervorbis.cpp	(working copy)
@@ -235,14 +235,31 @@
 
 // TODO: reinit encoder when samplerate or quality is updated
 
-int EncoderVorbis::initEncoder()
+int EncoderVorbis::initEncoder(float quality)
 {
     int ret;
     vorbis_info_init(&vinfo);
+    
+    // initialize VBR quality based mode
+    unsigned long samplerate = m_pConfig->getValueString(ConfigKey("[Soundcard]","Samplerate")).toULong();
+    ret = vorbis_encode_init_vbr(&vinfo, 2, samplerate, quality);
+    
+    if (ret == 0) {
+        initStream();
+    } else {
+        ret = -1;
+    };
+    return ret;
+}
 
+int EncoderVorbis::initEncoder(int bitrate)
+{
+    int ret;
+    vorbis_info_init(&vinfo);
+
     // initialize VBR quality based mode
     unsigned long samplerate = m_pConfig->getValueString(ConfigKey("[Soundcard]","Samplerate")).toULong();
-    ret = vorbis_encode_init_vbr(&vinfo, 2, samplerate, 0.4);
+    ret = vorbis_encode_init(&vinfo, 2, samplerate, -1, bitrate*1000, -1);
 
     if (ret == 0) {
         initStream();
@@ -251,3 +268,8 @@
     };
     return ret;
 }
+
+int EncoderVorbis::initEncoder()
+{
+    return this->initEncoder((float)0.4);
+}
Index: src/encodervorbis.h
===================================================================
--- src/encodervorbis.h	(revision 2643)
+++ src/encodervorbis.h	(working copy)
@@ -20,23 +20,26 @@
 #include <QObject>
 #include "defs.h"
 #include "configobject.h"
+#include "encoder.h"
 
 #include <vorbis/vorbisenc.h> // this also includes vorbis/codec.h
 
 class EngineAbstractRecord;
 class TrackInfoObject;
 
-class EncoderVorbis : public QObject {
+class EncoderVorbis : public Encoder {
     Q_OBJECT
 
 public:
     EncoderVorbis(ConfigObject<ConfigValue> *_config, EngineAbstractRecord *engine=0);
     ~EncoderVorbis();
     int initEncoder();
+    int initEncoder(float quality);
+    int initEncoder(int bitrate);
     void encodeBuffer(const CSAMPLE *samples, const int size);
-    bool metaDataHasChanged();
 
-public slots:
+
+private slots:
     void updateMetaData(TrackInfoObject *trackInfoObj);
 
 private:
@@ -44,6 +47,7 @@
     void flushStream();
     void initStream();
     void sendPackages();
+    bool metaDataHasChanged();
 
     ConfigObject<ConfigValue> *m_pConfig; /* provides ConfigKey access */
     ogg_stream_state oggs;    /* take physical pages, weld into logical stream
Index: src/engine/engineshoutcast.h
===================================================================
--- src/engine/engineshoutcast.h	(revision 2643)
+++ src/engine/engineshoutcast.h	(working copy)
@@ -28,6 +28,8 @@
 
 #include <QObject>
 
+#include "encoder.h"
+
 //class ControlLogpotmeter;
 //class ConfigKey;
 class EncoderVorbis;
@@ -54,7 +56,7 @@
     long m_iShoutStatus;
     ConfigObject<ConfigValue> *m_pConfig;
     ControlObject* recReady;
-    EncoderVorbis *encoder;
+    Encoder *encoder;
     ControlObjectThreadMain* m_pUpdateShoutcastFromPrefs;
 //    void (*writeFn)(unsigned char *, unsigned char *, int, int);
 };
Index: src/SConscript
===================================================================
--- src/SConscript	(revision 2643)
+++ src/SConscript	(working copy)
@@ -802,8 +802,9 @@
 #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 encodervorbis.cpp """ )
+	sources += Split(""" dlgprefshoutcast.cpp engine/engineshoutcast.cpp encoder.cpp encodervorbis.cpp encodermp3.cpp""" )
 	env.Uic4('dlgprefshoutcastdlg.ui')
 	print "Shoutcast support... enabled"
 	build_flags += 'shoutcast '
Index: src/dlgprefshoutcastdlg.ui
===================================================================
--- src/dlgprefshoutcastdlg.ui	(revision 2643)
+++ src/dlgprefshoutcastdlg.ui	(working copy)
@@ -49,6 +49,16 @@
           <string>Icecast 2</string>
          </property>
         </item>
+        <item>
+         <property name="text" >
+          <string>Shoutcast</string>
+         </property>
+        </item>
+        <item>
+         <property name="text" >
+          <string>Icecast 1</string>
+         </property>
+        </item>
        </widget>
       </item>
       <item row="0" column="2" >
@@ -321,6 +332,31 @@
             <string>128 kbps</string>
            </property>
           </item>
+          <item>
+           <property name="text" >
+            <string>112 kbps</string>
+           </property>
+          </item>
+          <item>
+           <property name="text" >
+            <string>96 kbps</string>
+           </property>
+          </item>
+          <item>
+           <property name="text" >
+            <string>80 kbps</string>
+           </property>
+          </item>
+          <item>
+           <property name="text" >
+            <string>64 kbps</string>
+           </property>
+          </item>
+          <item>
+           <property name="text" >
+            <string>48 kbps</string>
+           </property>
+          </item>
          </widget>
         </item>
        </layout>
@@ -347,6 +383,11 @@
             <string>Ogg Vorbis</string>
            </property>
           </item>
+          <item>
+           <property name="text" >
+            <string>MP3</string>
+           </property>
+          </item>
          </widget>
         </item>
        </layout>
------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H
_______________________________________________
Mixxx-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mixxx-devel

Reply via email to