aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/DSP/dsp_sc/sc2srclib
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Plugins/DSP/dsp_sc/sc2srclib')
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/_ptrlist.h411
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder.cpp95
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder.h53
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_aacp.cpp84
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_aacp.h37
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_fhgaac.cpp80
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_fhgaac.h33
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_mp3dll.cpp105
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_mp3dll.h51
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_nsv.cpp151
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_nsv.h76
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_ogg.cpp117
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_ogg.h47
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/enc_if.h44
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/Include/c_jobmanager.h254
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/Include/c_serial_jobmanager.h24
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/Include/c_shoutcast_2_output.h194
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/Include/shoutcast_output.h817
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/lame/include/lame.h1323
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/lame/libmp3lame/lame_global_flags.h184
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/shoutcast_output.cpp1636
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/uvAuth21/uvAuth21.cpp90
-rw-r--r--Src/Plugins/DSP/dsp_sc/sc2srclib/uvAuth21/uvAuth21.h34
23 files changed, 5940 insertions, 0 deletions
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/_ptrlist.h b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/_ptrlist.h
new file mode 100644
index 00000000..d81a8b7c
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/_ptrlist.h
@@ -0,0 +1,411 @@
+//PORTABLE
+#ifndef _PTRLIST_H
+#define _PTRLIST_H
+
+#define POS_LAST -1
+
+// 1k each, leaving 16 bytes for MALLOC overhead
+#define PTRLIST_INCREMENT 252
+
+template<class T>
+class PtrList
+{
+public:
+ PtrList()
+ {
+ nitems = 0;
+ nslots = 0;
+ items = NULL;
+ }
+
+ PtrList( PtrList<T> *other )
+ {
+ nitems = other->nitems;
+ nslots = other->nslots;
+ items = (T **)memdup( other->items, nslots * sizeof( T * ) );
+ }
+
+ virtual ~PtrList()
+ {
+ if ( items )
+ free( items );
+ }
+
+ int getNumItems() { return nitems; };
+
+ T *enumItem( int n )
+ {
+ if ( items == NULL )
+ return NULL;
+
+ if ( n < 0 )
+ return NULL;
+
+ if ( n >= nitems )
+ return NULL;
+
+ return items[ n ];
+ }
+
+ T *operator[]( int n ) { return enumItem( n ); }
+
+// this will safely return NULL if 0 items due to enumItems's boundscheck
+ T *getFirst() { return enumItem( 0 ); }
+
+ T *getLast() { return enumItem( nitems - 1 ); }
+
+ virtual T *addItem( T *item, int pos = POS_LAST )
+ {
+// ASSERTPR(item != NULL, "can't put NULLs into ptrlists");
+// ASSERT(nitems <= nslots);
+ if ( items == NULL )
+ {
+ nslots = PTRLIST_INCREMENT;
+ items = (T **)malloc( sizeof( T * ) * nslots );
+ nitems = 0;
+ }
+ else if ( nslots == nitems )
+ { // time to expand
+ T **newitems;
+ nslots += PTRLIST_INCREMENT;
+ newitems = (T **)malloc( sizeof( T * ) * nslots );
+ memcpy( newitems, items, nitems * sizeof( T * ) );
+
+ if ( items )
+ free( items );
+
+ items = newitems;
+ }
+
+ _addToList( item );
+ if ( pos != POS_LAST )
+ moveItem( nitems - 1, pos );
+
+ return item;
+ }
+
+ // FG> avoid using this before i tested it more
+ void moveItem( int from, int to )
+ {
+ if ( from == to )
+ return;
+
+ T *ptr = items[ from ];
+
+ if ( nitems > from + 1 ) // if moving from the end, there is nothing to shift behind our src position
+ //IMPORTANT note for future ports: This assumes MEMCPY accepts overlapping segments.
+ memcpy( &items[ from ], &items[ from + 1 ], ( nitems - from ) * sizeof( T * ) );
+
+ if ( to > from )
+ to--;
+
+ if ( nitems > to ) // if moving to the end, there is nothing to shift behind our target position
+ memcpy( &items[ to + 1 ], &items[ to ], ( nitems - to - 1 ) * sizeof( T * ) );
+
+ items[ to ] = ptr;
+ }
+
+ // deletes first instance of a pointer in list, returns how many are left
+ int delItem( T *item )
+ {
+ int c = 0;
+
+ if ( item == NULL || items == NULL || nitems <= 0 )
+ return 0;
+
+ // count occurences of item in items, remember the first one
+ T **p = items;
+ int first = -1;
+
+ for ( int i = 0; i < nitems; i++, p++ )
+ {
+ if ( *p == item )
+ {
+ if ( c++ == 0 )
+ first = i;
+ }
+ }
+
+ // if we found one, remove it
+ if ( c > 0 )
+ {
+ delByPos( first ); // delByPos is faaast
+ c--; // decrease count
+ }
+
+ return c; // returns how many occurences of this item left
+ }
+
+ // removes all instances of this pointer
+ void delEveryItem( T *item ) { while ( delItem( item ) ); }
+
+ // removes pointer at specified pos
+ void delByPos( int pos )
+ {
+ if ( pos < 0 || pos >= nitems )
+ return; //JC
+
+ --nitems;
+ if ( pos == nitems )
+ return; // last one? nothing to copy over
+
+ memcpy( items + pos, items + ( pos + 1 ), sizeof( T * ) * ( nitems - pos ) ); // CT:not (nitems-(pos+1)) as nitems has been decremented earlier
+ }
+
+ // removes last item, leaving pointer alone
+ void removeLastItem()
+ {
+ if ( nitems == 0 || items == NULL )
+ return;
+
+ nitems--; // hee hee
+ }
+
+ // removes all entries, leaving pointers alone
+ void removeAll()
+ {
+ if ( items )
+ free( items );
+
+ items = NULL;
+ nitems = 0;
+ nslots = 0;
+ }
+
+ // removes all entries, calling FREE on the pointers
+ void freeAll()
+ {
+ for ( int i = 0; i < nitems; i++ ) //JC
+ if ( items )
+ free( items[ i ] );
+
+ removeAll();
+ }
+
+ // removes all entries, calling delete on the pointers
+ void deleteAll()
+ {
+ int i;
+ if ( items == NULL || nitems <= 0 )
+ return; //JC
+
+ for ( i = 0; i < nitems; i++ )
+ { //JC
+ delete items[ i ];
+ }
+
+ removeAll();
+ }
+
+ virtual int haveItem( T *item )
+ {// gross-ass linear search to see if we have it
+ for ( int i = 0; i < nitems; i++ ) //JC
+ if ( items[ i ] == item )
+ return 1;
+
+ return 0;
+ }
+
+ virtual int searchItem( T *item )
+ { // gross-ass linear search to find index of item
+ for ( int i = 0; i < getNumItems(); i++ )
+ if ( items[ i ] == item )
+ return i;
+
+ return -1;
+ }
+
+protected:
+ virtual void _addToList( T *item ) { items[ nitems++ ] = item; }
+
+ int nitems, nslots;
+ T **items;
+};
+
+template<class T>
+class PtrListBaseSorted : public PtrList<T>
+{
+public:
+ virtual T *findItem( char *attrib )
+ {
+#if 1
+ if ( nitems == 0 || items == NULL )
+ return NULL;
+
+ int bot = 0, top = nitems - 1;
+
+ for ( int c = 0; c < nitems + 16; c++ )
+ {
+ if ( bot > top )
+ return NULL;
+
+ int mid = ( bot + top ) / 2;
+ int r = compareAttrib( attrib, items[ mid ] );
+
+ if ( r == 0 )
+ return items[ mid ];
+
+ if ( r < 0 )
+ {
+ top = mid - 1;
+ }
+ else
+ {
+ bot = mid + 1;
+ }
+ }
+ // ASSERTPR(0, "binary search fucked up");
+#else
+ for ( int i = 0; i < nitems; i++ )
+ {
+ if ( compareAttrib( attrib, items[ i ] ) == 0 )
+ return items[ i ];
+ }
+#endif
+ return NULL;
+ }
+
+protected:
+ // comparator for searching -- override
+ virtual int compareAttrib( char *attrib, T *item ) = 0;
+
+ // comparator for sorting -- override , -1 p1 < p2, 0 eq, 1 p1 > p2
+ virtual int compareItem( T *p1, T *p2 ) = 0;
+};
+
+
+#if 0
+// try not to use this
+template<class T>
+class PtrListSortedInsertion : public PtrListBaseSorted<T>
+{
+protected:
+ virtual void _addToList( T *item )
+ {
+ if ( nitems == 0 )
+ {
+ items[ nitems++ ] = item;
+
+ return;
+ }
+
+ for ( int i = 0; i < nitems; i++ )
+ {
+ if ( compareItem( items[ i ], item ) == 1 )
+ {
+ T *tmp = items[ i ];
+ items[ i ] = item;
+ for ( int j = i + 1; j < nitems; j++ )
+ {
+ T *tmp2 = items[ j ];
+ items[ j ] = tmp;
+ tmp = tmp2;
+ }
+
+ items[ nitems++ ] = tmp;
+
+ return;
+ }
+ }
+
+ items[ nitems++ ] = item;
+
+ return;
+ }
+};
+#endif
+
+// a base class to defer sorting until lookup
+template<class T>
+class PtrListSorted : public PtrListBaseSorted<T>
+{
+public:
+ PtrListSorted()
+ {
+ nitems = 0;
+ nslots = 0;
+ items = NULL;
+ need_sorting = 0;
+ }
+
+ virtual T *addItem( T *item )
+ {
+ need_sorting = 1;
+
+ return PtrList<T>::addItem( item );
+ }
+
+ virtual T *findItem( char *attrib )
+ {
+ sort();
+
+ return PtrListBaseSorted<T>::findItem( attrib );
+ }
+
+ int needSort() { return need_sorting; }
+
+ void sort()
+ {
+ if ( need_sorting )
+ _sort();
+
+ need_sorting = 0;
+ }
+
+private:
+ int need_sorting;
+
+ virtual void _sort() = 0;
+};
+
+template<class T>
+class PtrListQuickSorted : public PtrListSorted<T>
+{
+public:
+ virtual void _sort()
+ {
+ if ( items == NULL || nitems <= 1 )
+ return;
+
+ Qsort( 0, nitems - 1 );
+ }
+
+ void swap( int a, int b )
+ {
+ T *tmp = items[ a ];
+ items[ a ] = items[ b ];
+ items[ b ] = tmp;
+ }
+
+ void Qsort( int lo0, int hi0 )
+ {
+ int lo = lo0, hi = hi0;
+ if ( hi0 > lo0 )
+ {
+ T *mid = enumItem( ( lo0 + hi0 ) / 2 );
+ while ( lo <= hi )
+ {
+ while ( ( lo < hi0 ) && ( compareItem( items[ lo ], mid ) < 0 ) )
+ lo++;
+
+ while ( ( hi > lo0 ) && ( compareItem( items[ hi ], mid ) > 0 ) )
+ hi--;
+
+ if ( lo <= hi )
+ {
+ swap( lo, hi );
+ lo++;
+ hi--;
+ }
+ }
+
+ if ( lo0 < hi )
+ Qsort( lo0, hi );
+
+ if ( lo < hi0 )
+ Qsort( lo, hi0 );
+ }
+ }
+};
+
+#endif
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder.cpp b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder.cpp
new file mode 100644
index 00000000..a2a3f2fe
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder.cpp
@@ -0,0 +1,95 @@
+#include <windows.h>
+#include "c_encoder.h"
+
+C_ENCODER::C_ENCODER(int ExtInfoSize) {
+ SetName("Untyped Encoder");
+ ExtendedInfoPtr = (T_EncoderIOVals *)malloc(ExtInfoSize);
+ ExtendedInfoSize = ExtInfoSize;
+}
+
+C_ENCODER::~C_ENCODER() {
+ Close();
+ if(ExtendedInfoPtr && ExtendedInfoSize) free(ExtendedInfoPtr);
+ ExtendedInfoSize = 0;
+}
+
+void C_ENCODER::Close() {
+ ClearAttribs();
+}
+
+void C_ENCODER::SetName(const char *name) {
+ if (name) lstrcpyn(Name, name, C_ENCODER_NameLen);
+}
+
+char *C_ENCODER::GetName() {
+ return Name;
+}
+
+void C_ENCODER::Reset() {
+}
+
+void C_ENCODER::ChangeSettings(const void *Settings) {
+ if(ExtendedInfoPtr && ExtendedInfoSize && Settings && Settings != ExtendedInfoPtr) {
+ memcpy(ExtendedInfoPtr,Settings,ExtendedInfoSize);
+ Reset();
+ }
+}
+
+void C_ENCODER::Create(const T_EncoderIOVals *Settings, const char *name) {
+ if(name) SetName(name);
+ ChangeSettings(Settings);
+}
+
+void C_ENCODER::ClearAttribs() {
+ for(int i = AttribList.size()-1; i >= 0; i--) {
+ T_ATTRIB *myAttrib = AttribList[i];
+ if(myAttrib->OutputVals) delete[] myAttrib->OutputVals;
+ }
+
+ //AttribList.deleteAll();
+ for (auto attrib : AttribList)
+ {
+ delete attrib;
+ }
+ AttribList.clear();
+}
+
+void C_ENCODER::AddAttrib(const char *Text, const void *Attributes) {
+ T_ATTRIB *myAttrib = new T_ATTRIB;
+ if(Text!=NULL) {
+ ::strncpy((char *)&myAttrib->Text,Text,sizeof(myAttrib->Text));
+ } else {
+ ::strncpy((char *)&myAttrib->Text,"<This should never appear here...>",sizeof(myAttrib->Text));
+ }
+ myAttrib->OutputVals = (T_EncoderIOVals *)Attributes;
+ AttribList.push_back(myAttrib);
+}
+
+int C_ENCODER::Encode(const void *inputbuf, const unsigned int inputbufsize, void *outputbuf, const unsigned int outputbufsize, int *inputamtused) {
+ if((inputbuf != NULL) && (outputbuf != NULL) && (inputbufsize != 0) && (outputbufsize != 0) && (inputamtused != NULL)) {
+ int numitems = (inputbufsize > outputbufsize) ? outputbufsize : inputbufsize;
+ memcpy(outputbuf,inputbuf,numitems);
+ *inputamtused = numitems;
+ return numitems;
+ }
+ return 0;
+}
+
+int C_ENCODER::GetNumAttribs() {
+ return AttribList.size();
+}
+
+int C_ENCODER::EnumAttrib(const int val, T_ATTRIB *buf) {
+ if((val < 0)||(val >= AttribList.size())||(buf==NULL)) return 0;
+ T_ATTRIB *myattrib = AttribList[val];
+ if(myattrib==NULL) return 0;
+ ::memcpy(buf,myattrib,sizeof(T_ATTRIB));
+ return 1;
+}
+
+char * C_ENCODER::GetContentType() {
+
+ //if(strcmp(this->GetName(), "MP3 Encoder") == 0)
+ return "audio/mpeg";
+
+} \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder.h b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder.h
new file mode 100644
index 00000000..04ef9220
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder.h
@@ -0,0 +1,53 @@
+#ifndef __C_ENCODER_H__
+#define __C_ENCODER_H__
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <vector>
+
+#define C_ENCODER_NameLen 1024
+
+struct T_EncoderIOVals {
+ unsigned int output_bitRate;
+};
+
+struct T_ATTRIB {
+ char Text[256];
+void *OutputVals;
+};
+
+class C_ENCODER {
+private:
+ char Name[C_ENCODER_NameLen];
+ std::vector<T_ATTRIB*> AttribList;
+protected:
+ T_EncoderIOVals *ExtendedInfoPtr;
+ int ExtendedInfoSize;
+ void SetName(const char *name);
+ void ClearAttribs();
+ void AddAttrib(const char *Text, const void *Attributes);
+public:
+ C_ENCODER(int ExtInfoSize = 0);
+ virtual ~C_ENCODER();
+
+ virtual void ChangeSettings(const void *Settings);
+ virtual void Create(const T_EncoderIOVals *Settings, const char *name = NULL);
+ virtual void Close();
+ virtual void Reset();
+ virtual char *GetName();
+ virtual void *GetExtInfo(int *ExtInfoSize = NULL) {
+ if(ExtInfoSize != NULL) *ExtInfoSize = ExtendedInfoSize;
+ return ExtendedInfoPtr;
+ }
+
+ virtual char * GetContentType();
+ virtual int Encode(const void *inputbuf, const unsigned int inputbufsize, void *outputbuf, const unsigned int outputbufsize, int *inputamtused); /* all values are in BYTES! */
+
+ virtual int GetNumAttribs();
+ virtual int EnumAttrib(const int val, T_ATTRIB *buf);
+
+ virtual bool UseNsvConfig() { return false; }
+};
+
+#endif /* !__C_ENCODER_H__ */ \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_aacp.cpp b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_aacp.cpp
new file mode 100644
index 00000000..62a09e89
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_aacp.cpp
@@ -0,0 +1,84 @@
+#include "c_encoder_aacp.h"
+#include "../../utils.h"
+
+HINSTANCE C_ENCODER_AACP::hEncoderInstance = NULL;
+
+C_ENCODER_AACP::C_ENCODER_AACP(HWND winamp) : C_ENCODER_NSV(sizeof(T_ENCODER_AACP_INFO)) {
+ SetName("AAC+ Encoder");
+ winampWnd = winamp;
+ ConfigAudio3 = NULL;
+ if(hEncoderInstance == NULL) {
+ wchar_t dir[MAX_PATH] = {0};
+ snwprintf(dir, MAX_PATH, L"%s\\enc_aacplus.dll", GetPluginDirectoryW(winamp));
+ hEncoderInstance = LoadLibraryW(dir);
+ }
+
+ if(hEncoderInstance) {
+ void * CreateAudio3=(void *)GetProcAddress(hEncoderInstance, "CreateAudio3");
+ void * GetAudioTypes3=(void *)GetProcAddress(hEncoderInstance, "GetAudioTypes3");
+ void * ConfigAudio3=(void *)GetProcAddress(hEncoderInstance, "ConfigAudio3");
+ void * SetWinampHWND=(void *)GetProcAddress(hEncoderInstance, "SetWinampHWND");
+ SetEncoder(CreateAudio3,GetAudioTypes3,ConfigAudio3,SetWinampHWND);
+ }
+
+ T_ENCODER_AACP_INFO * EncInfo = (T_ENCODER_AACP_INFO *)ExtendedInfoPtr;
+ EncInfo->output_bitRate = AACP_DEFAULT_OUTPUTBITRATE;
+ EncInfo->output_channelmode = AACP_DEFAULT_OUTPUTCHANNELMODE;
+ EncInfo->output_quality = AACP_DEFAULT_OUTPUTQUALITY;
+ EncInfo->output_samplerate = AACP_DEFAULT_OUTPUTSAMPLERATE;
+ EncInfo->output_v2enable = AACP_DEFAULT_OUTPUTV2ENABLE;
+}
+
+C_ENCODER_AACP::~C_ENCODER_AACP() {
+ C_ENCODER_NSV::~C_ENCODER_NSV();
+}
+
+static int cacheVal=0;
+bool C_ENCODER_AACP::isPresent(HWND winamp) {
+ if(cacheVal!=0 && hEncoderInstance!=0) return cacheVal==2;
+ bool ret=false;
+ wchar_t dir[MAX_PATH] = {0};
+ snwprintf(dir, MAX_PATH, L"%s\\enc_aacplus.dll", GetPluginDirectoryW(winamp));
+ FILE * f = _wfopen(dir, L"rb");
+ if (f) {
+ fseek(f,0,2);
+ if(ftell(f) > 0) ret=true;
+ fclose(f);
+ }
+ cacheVal=ret?2:1;
+ return ret;
+}
+
+void C_ENCODER_AACP::FillAttribs() {
+ T_ENCODER_AACP_INFO &EncInfo = *(T_ENCODER_AACP_INFO *)ExtendedInfoPtr;
+ T_ENCODER_AACP_INFO *attribs = new T_ENCODER_AACP_INFO;
+ *attribs = EncInfo;
+ AddAttrib("",attribs);
+}
+
+void C_ENCODER_AACP::FillConfFile(char * conf_file, char * section) {
+ if(!section) section="audio_aacplus";
+
+ T_ENCODER_AACP_INFO &EncInfo = *(T_ENCODER_AACP_INFO *)ExtendedInfoPtr;
+
+ WritePrivateProfileInt("samplerate", EncInfo.output_samplerate, section, conf_file);
+ WritePrivateProfileInt("channelmode", EncInfo.output_channelmode, section, conf_file);
+ WritePrivateProfileInt("bitrate", EncInfo.output_bitRate * 1000, section, conf_file);
+ WritePrivateProfileInt("v2enable", EncInfo.output_v2enable, section, conf_file);
+}
+
+void C_ENCODER_AACP::ReadConfFile(char * conf_file, char * section) {
+ if(!section) section="audio_aacplus";
+
+ T_ENCODER_AACP_INFO &EncInfo = *(T_ENCODER_AACP_INFO *)ExtendedInfoPtr;
+ T_ENCODER_AACP_INFO *attribs = new T_ENCODER_AACP_INFO;
+ *attribs = EncInfo;
+
+ attribs->output_samplerate = GetPrivateProfileInt(section,"samplerate",AACP_DEFAULT_OUTPUTSAMPLERATE,conf_file);
+ attribs->output_channelmode = GetPrivateProfileInt(section,"channelmode",AACP_DEFAULT_OUTPUTCHANNELMODE,conf_file);
+ attribs->output_bitRate = GetPrivateProfileInt(section,"bitrate",AACP_DEFAULT_OUTPUTBITRATE,conf_file)/1000;
+ attribs->output_quality = GetPrivateProfileInt(section,"quality",AACP_DEFAULT_OUTPUTQUALITY,conf_file);
+ attribs->output_v2enable = GetPrivateProfileInt(section,"v2enable",AACP_DEFAULT_OUTPUTV2ENABLE,conf_file);
+
+ ChangeSettings(attribs);
+} \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_aacp.h b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_aacp.h
new file mode 100644
index 00000000..f6028169
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_aacp.h
@@ -0,0 +1,37 @@
+#ifndef __C_ENCODER_AACP_H__
+#define __C_ENCODER_AACP_H__
+
+#include "c_encoder_nsv.h"
+
+struct T_ENCODER_AACP_INFO : public T_ENCODER_NSV_INFO
+{
+ unsigned int output_quality;
+ unsigned int output_samplerate;
+ unsigned int output_channelmode;
+ unsigned int output_v2enable;
+};
+
+#define AACP_DEFAULT_OUTPUTCHANNELMODE 4
+#define AACP_DEFAULT_OUTPUTBITRATE 48
+#define AACP_DEFAULT_OUTPUTQUALITY 2
+#define AACP_DEFAULT_OUTPUTSAMPLERATE 44100
+#define AACP_DEFAULT_OUTPUTV2ENABLE 1
+
+class C_ENCODER_AACP : public C_ENCODER_NSV {
+private:
+ HWND winamp;
+protected:
+ virtual void FillAttribs();
+public:
+ static HINSTANCE hEncoderInstance;
+ C_ENCODER_AACP(HWND hwnd = 0);
+ virtual ~C_ENCODER_AACP();
+ static bool isPresent(HWND winamp);
+ virtual void ReadConfFile(char * conf_file, char * section=NULL);
+ virtual void FillConfFile(char * conf_file, char * section=NULL);
+ static void Unload() { if(hEncoderInstance) FreeLibrary(hEncoderInstance); hEncoderInstance=0; }
+ virtual char * GetContentType() { return "audio/aacp"; }
+ virtual HINSTANCE GetEncoderInstance() { return hEncoderInstance; }
+};
+
+#endif /* !__C_ENCODER_AACP_H__ */ \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_fhgaac.cpp b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_fhgaac.cpp
new file mode 100644
index 00000000..749988d2
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_fhgaac.cpp
@@ -0,0 +1,80 @@
+#include "c_encoder_fhgaac.h"
+#include "../../utils.h"
+
+HINSTANCE C_ENCODER_FHGAAC::hEncoderInstance = NULL;
+
+C_ENCODER_FHGAAC::C_ENCODER_FHGAAC(HWND winamp) : C_ENCODER_NSV(sizeof(T_ENCODER_FHGAAC_INFO)) {
+ SetName("Fraunhofer Encoder");
+ winampWnd = winamp;
+ ConfigAudio3 = NULL;
+ if(hEncoderInstance == NULL) {
+ wchar_t dir[MAX_PATH] = {0};
+ snwprintf(dir, MAX_PATH, L"%s\\enc_fhgaac.dll", GetPluginDirectoryW(winamp));
+ hEncoderInstance = LoadLibraryW(dir);
+ }
+
+ if(hEncoderInstance) {
+ void * CreateAudio3=(void *)GetProcAddress(hEncoderInstance, "CreateAudio3");
+ void * GetAudioTypes3=(void *)GetProcAddress(hEncoderInstance, "GetAudioTypes3");
+ void * ConfigAudio3=(void *)GetProcAddress(hEncoderInstance, "ConfigAudio3");
+ void * SetWinampHWND=(void *)GetProcAddress(hEncoderInstance, "SetWinampHWND");
+ SetEncoder(CreateAudio3,GetAudioTypes3,ConfigAudio3,SetWinampHWND,1);
+ }
+
+ T_ENCODER_FHGAAC_INFO * EncInfo = (T_ENCODER_FHGAAC_INFO *)ExtendedInfoPtr;
+ EncInfo->output_bitRate = FHGAAC_DEFAULT_OUTPUTBITRATE;
+ EncInfo->output_profile = FHGAAC_DEFAULT_OUTPUTPROFILE;
+ EncInfo->output_surround = FHGAAC_DEFAULT_OUTPUTSURROUND;
+}
+
+C_ENCODER_FHGAAC::~C_ENCODER_FHGAAC() {
+ C_ENCODER_NSV::~C_ENCODER_NSV();
+}
+
+static int cacheVal=0;
+bool C_ENCODER_FHGAAC::isPresent(HWND winamp) {
+ if(cacheVal!=0 && hEncoderInstance!=0) return cacheVal==2;
+ bool ret=false;
+ wchar_t dir[MAX_PATH] = {0};
+ snwprintf(dir, MAX_PATH, L"%s\\enc_fhgaac.dll", GetPluginDirectoryW(winamp));
+ FILE * f = _wfopen(dir, L"rb");
+ if (f) {
+ fseek(f,0,2);
+ if(ftell(f) > 0) ret=true;
+ fclose(f);
+ }
+ cacheVal=ret?2:1;
+ return ret;
+}
+
+void C_ENCODER_FHGAAC::FillAttribs() {
+ T_ENCODER_FHGAAC_INFO &EncInfo = *(T_ENCODER_FHGAAC_INFO *)ExtendedInfoPtr;
+ T_ENCODER_FHGAAC_INFO *attribs = new T_ENCODER_FHGAAC_INFO;
+ *attribs = EncInfo;
+ AddAttrib("",attribs);
+}
+
+void C_ENCODER_FHGAAC::FillConfFile(char * conf_file, char * section) {
+ if(!section) section="audio_adtsaac";
+
+ T_ENCODER_FHGAAC_INFO &EncInfo = *(T_ENCODER_FHGAAC_INFO *)ExtendedInfoPtr;
+
+ WritePrivateProfileInt("profile", EncInfo.output_profile, section, conf_file);
+ WritePrivateProfileInt("bitrate", EncInfo.output_bitRate, section, conf_file);
+ WritePrivateProfileInt("surround", EncInfo.output_surround, section, conf_file);
+ WritePrivateProfileInt("shoutcast", 1, section, conf_file);
+}
+
+void C_ENCODER_FHGAAC::ReadConfFile(char * conf_file, char * section) {
+ if(!section) section="audio_adtsaac";
+
+ T_ENCODER_FHGAAC_INFO &EncInfo = *(T_ENCODER_FHGAAC_INFO *)ExtendedInfoPtr;
+ T_ENCODER_FHGAAC_INFO *attribs = new T_ENCODER_FHGAAC_INFO;
+ *attribs = EncInfo;
+
+ attribs->output_profile = GetPrivateProfileInt(section,"profile",FHGAAC_DEFAULT_OUTPUTPROFILE,conf_file);
+ attribs->output_bitRate = GetPrivateProfileInt(section,"bitrate",FHGAAC_DEFAULT_OUTPUTBITRATE,conf_file);
+ attribs->output_surround = GetPrivateProfileInt(section,"surround",FHGAAC_DEFAULT_OUTPUTSURROUND,conf_file);
+
+ ChangeSettings(attribs);
+} \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_fhgaac.h b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_fhgaac.h
new file mode 100644
index 00000000..67071945
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_fhgaac.h
@@ -0,0 +1,33 @@
+#ifndef __C_ENCODER_FHGAAC_H__
+#define __C_ENCODER_FHGAAC_H__
+
+#include "c_encoder_nsv.h"
+
+struct T_ENCODER_FHGAAC_INFO : public T_ENCODER_NSV_INFO
+{
+ unsigned int output_profile;
+ unsigned int output_surround;
+};
+
+#define FHGAAC_DEFAULT_OUTPUTBITRATE 48
+#define FHGAAC_DEFAULT_OUTPUTPROFILE 0 // automatic
+#define FHGAAC_DEFAULT_OUTPUTSURROUND 0
+
+class C_ENCODER_FHGAAC : public C_ENCODER_NSV {
+private:
+ HWND winamp;
+protected:
+ virtual void FillAttribs();
+public:
+ static HINSTANCE hEncoderInstance;
+ C_ENCODER_FHGAAC(HWND hwnd = 0);
+ virtual ~C_ENCODER_FHGAAC();
+ static bool isPresent(HWND winamp);
+ virtual void ReadConfFile(char * conf_file, char * section=NULL);
+ virtual void FillConfFile(char * conf_file, char * section=NULL);
+ static void Unload() { if(hEncoderInstance) FreeLibrary(hEncoderInstance); hEncoderInstance=0; }
+ virtual char * GetContentType() { return "audio/aacp"; }
+ virtual HINSTANCE GetEncoderInstance() { return hEncoderInstance; }
+};
+
+#endif /* !__C_ENCODER_AACP_H__ */ \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_mp3dll.cpp b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_mp3dll.cpp
new file mode 100644
index 00000000..4a703b24
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_mp3dll.cpp
@@ -0,0 +1,105 @@
+#include "c_encoder_mp3dll.h"
+#include "../../utils.h"
+
+T_ENCODER_MP3_INFO formatlist[] = {
+ {8, 22050, 1, 44100, 2, 8}, {16, 22050, 1, 44100, 2, 8}, {24, 22050, 1, 44100, 2, 8},
+ {32, 22050, 1, 44100, 2, 8}, {40, 22050, 1, 44100, 2, 8}, {48, 22050, 1, 44100, 2, 8},
+ {48, 44100, 1, 44100, 2, 8}, {56, 22050, 1, 44100, 2, 8}, {56, 44100, 1, 44100, 2, 8},
+ {64, 44100, 1, 44100, 2, 8}, {80, 44100, 1, 44100, 2, 8}, {96, 44100, 1, 44100, 2, 8},
+ {112, 44100, 1, 44100, 2, 8}, {128, 44100, 1, 44100, 2, 8}, {40, 22050, 2, 44100, 2, 8},
+ {48, 22050, 2, 44100, 2, 8}, {56, 22050, 2, 44100, 2, 8}, {64, 22050, 2, 44100, 2, 8},
+ {80, 22050, 2, 44100, 2, 8}, {56, 44100, 2, 44100, 2, 8}, {64, 44100, 2, 44100, 2, 8},
+ {80, 44100, 2, 44100, 2, 8}, {96, 44100, 2, 44100, 2, 8}, {112, 44100, 2, 44100, 2, 8},
+ {128, 44100, 2, 44100, 2, 8}, {160, 44100, 2, 44100, 2, 8}, {192, 44100, 2, 44100, 2, 8},
+ {224, 44100, 2, 44100, 2, 8}, {256, 44100, 2, 44100, 2, 8}, {320, 44100, 2, 44100, 2, 8}
+};
+
+static unsigned int formatlist_numEntries = sizeof(formatlist) / sizeof(T_ENCODER_MP3_INFO);
+
+C_ENCODER_MP3::C_ENCODER_MP3(void *init, void *params, void *encode, void *finish) : C_ENCODER(sizeof(T_ENCODER_MP3_INFO)) { //sizeof(T_ENCODER_LAMEMP3_INFO)
+ SetName("MP3 Encoder");
+ T_ENCODER_MP3_INFO &EncInfo = *((T_ENCODER_MP3_INFO *)ExtendedInfoPtr);
+ Handle = NULL;
+ has_encoded = 0;
+ EncInfo = formatlist[MP3_DEFAULT_ATTRIBNUM];
+ hMutex = CreateMutex(NULL,TRUE,NULL);
+ ReleaseMutex(hMutex);
+
+ lame_init = (lame_t (__cdecl *)(void))init;
+ lame_init_params = (int (__cdecl *)(lame_global_flags *))params;
+ lame_encode_buffer_interleaved = (int (__cdecl *)(lame_global_flags *, short int pcm[], int num_samples, char *mp3buffer, int mp3buffer_size))encode;
+ lame_encode_flush = (int (__cdecl *)(lame_global_flags *, char *mp3buffer, int size))finish;
+}
+
+C_ENCODER_MP3::~C_ENCODER_MP3() {
+ WaitForSingleObject(hMutex,INFINITE);
+ CloseHandle(hMutex);
+ hMutex = NULL;
+ C_ENCODER::~C_ENCODER();
+}
+
+void C_ENCODER_MP3::Close() {
+ C_ENCODER::Close();
+ if(lame_init != NULL) {
+ if(has_encoded && lame_encode_flush) {
+ char buf[1024] = {0};
+ lame_encode_flush(Handle,(char *)buf,sizeof(buf));
+ }
+ //delete Handle; caused crash !! needs looking at
+ Handle = NULL;
+ has_encoded = 0;
+ }
+}
+
+void C_ENCODER_MP3::Reset() {
+ T_ENCODER_MP3_INFO &EncInfo = *(T_ENCODER_MP3_INFO *)ExtendedInfoPtr;
+ if(WaitForSingleObject(hMutex,INFINITE) != WAIT_OBJECT_0) return;
+ Close();
+ if(lame_init != NULL && EncInfo.input_sampleRate != 0 && EncInfo.input_numChannels != 0) {
+ if(EncInfo.output_sampleRate != 0 && EncInfo.output_bitRate != 0 && Handle == NULL) {
+ has_encoded = 0;
+ Handle = lame_init();
+ Handle->samplerate_in = EncInfo.input_sampleRate;
+ Handle->num_channels = 2; // always process as 2 channels as it resolves issues with soundcard input in mono mode (which is padded to stereo)
+ Handle->samplerate_out = EncInfo.output_sampleRate;
+ Handle->mode = EncInfo.output_numChannels == 2 ? (MPEG_mode)0 : (MPEG_mode)3;
+ Handle->brate = EncInfo.output_bitRate;
+ Handle->VBR = vbr_off;
+ Handle->write_lame_tag = 0;
+ Handle->write_id3tag_automatic = 0;
+ Handle->quality = EncInfo.QualityMode;
+ if(Handle->quality < 0 || Handle->quality > 9) Handle->quality = 8;
+ lame_init_params(Handle);
+ } else {
+ Handle = NULL;
+ }
+ for(unsigned int i = 0; i < formatlist_numEntries; i++) {
+ char textbuf[256];
+ formatlist[i].QualityMode = EncInfo.QualityMode;
+ snprintf(textbuf,sizeof(textbuf),"%dkbps, %dHz, %s",formatlist[i].output_bitRate,formatlist[i].output_sampleRate,(formatlist[i].output_numChannels == 1 ? "Mono" : "Stereo"));
+ T_ENCODER_MP3_INFO *attribs = new T_ENCODER_MP3_INFO;
+ *attribs = formatlist[i];
+ AddAttrib((char *)&textbuf,attribs);
+ }
+ }
+ ReleaseMutex(hMutex);
+}
+
+int C_ENCODER_MP3::Encode(const void *inputbuf, const unsigned int inputbufsize, void *outputbuf, const unsigned int outputbufsize, int *inputamtused) {
+ if((inputbuf != NULL) && (outputbuf != NULL) && (inputbufsize != 0) && (outputbufsize != 0) && (inputamtused != NULL) && (Handle != NULL)) {
+ if(WaitForSingleObject(hMutex,INFINITE) != WAIT_OBJECT_0) return 0;
+ int outputamtused = 0;
+ if(lame_encode_buffer_interleaved) {
+ outputamtused = lame_encode_buffer_interleaved(Handle, (short *)inputbuf, inputbufsize / (2 * sizeof(short)), (char *)outputbuf, outputbufsize);
+ if(outputamtused < 0) {
+ ReleaseMutex(hMutex);
+ return 0;
+ }
+ has_encoded = 1;
+ }
+ *inputamtused = inputbufsize;
+ ReleaseMutex(hMutex);
+ return outputamtused;
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_mp3dll.h b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_mp3dll.h
new file mode 100644
index 00000000..05beb05e
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_mp3dll.h
@@ -0,0 +1,51 @@
+
+#ifndef __C_ENCODER_MP3DLL_H__
+#define __C_ENCODER_MP3DLL_H__
+
+#include "c_encoder.h"
+#include "../lame/include/lame.h"
+#include "../lame/libmp3lame/lame_global_flags.h"
+#include <windows.h>
+
+// Defaults for this encoder
+#define MP3_DEFAULT_INPUTSAMPLERATE 44100
+#define MP3_DEFAULT_INPUTNUMCHANNELS 2
+#define MP3_DEFAULT_OUTPUTSAMPLERATE 44100
+#define MP3_DEFAULT_OUTPUTNUMCHANNELS 2
+#define MP3_DEFAULT_OUTPUTBITRATE 96
+
+#define MP3_DEFAULT_ATTRIBNUM 22
+
+struct T_ENCODER_MP3_INFO {
+ int output_bitRate;
+ int output_sampleRate;
+ int output_numChannels;
+ int input_sampleRate;
+ int input_numChannels;
+ int QualityMode;
+};
+
+#define HBE_STREAM lame_global_flags *
+
+class C_ENCODER_MP3 : public C_ENCODER {
+private:
+ HANDLE hMutex;
+ lame_t Handle;
+ int has_encoded;
+protected:
+ lame_t (*lame_init)(void);
+ int (*lame_init_params)(lame_global_flags *);
+ int (*lame_encode_buffer_interleaved)(lame_global_flags *, short int pcm[], int num_samples, char *mp3buffer, int mp3buffer_size);
+ int (*lame_encode_flush)(lame_global_flags *, char *mp3buffer, int size);
+
+public:
+ C_ENCODER_MP3(void *init, void *params, void *encode, void *finish);
+ virtual ~C_ENCODER_MP3();
+
+ virtual void Close();
+ virtual void Reset();
+
+ virtual int Encode(const void *inputbuf, const unsigned int inputbufsize, void *outputbuf, const unsigned int outputbufsize, int *inputamtused); /* all values are in BYTES! */
+};
+
+#endif /* !__C_ENCODER_MP3_H__ */ \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_nsv.cpp b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_nsv.cpp
new file mode 100644
index 00000000..18098535
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_nsv.cpp
@@ -0,0 +1,151 @@
+#include "c_encoder_nsv.h"
+#include "../../utils.h"
+#include <mmsystem.h>
+#include <stdio.h>
+
+static char * configfile;
+static unsigned int configfourcc;
+static HWND (*ConfigAudio3)(HWND intParent, HINSTANCE hinst, unsigned int outt, char *configfile);
+static HINSTANCE encoderDllInstance;
+static HWND cfgwnd=NULL;
+C_ENCODER_NSV::C_ENCODER_NSV(int ExtInfoSize) : C_ENCODER(ExtInfoSize) {
+ hMutex = CreateMutex(NULL,TRUE,NULL);
+ ReleaseMutex(hMutex);
+ CreateAudio3 = NULL;
+ ConfigAudio3 = NULL;
+ GetAudioTypes3 = NULL;
+ SetWinampHWND = NULL;
+ SetConfigItem = NULL;
+ GetConfigItem = NULL;
+ winampWnd = NULL;
+ fourcc = 0;
+ encoder = NULL;
+}
+
+void C_ENCODER_NSV::SetEncoder(void * CreateAudio3, void * GetAudioTypes3, void * ConfigAudio3, void * SetWinampHWND, int encoderNum) {
+ *(void **)&(this->CreateAudio3) = CreateAudio3;
+ *(void **)&(this->GetAudioTypes3) = GetAudioTypes3;
+ *(void **)&(this->ConfigAudio3) = ConfigAudio3;
+ *(void **)&(this->SetWinampHWND) = SetWinampHWND;
+
+ if(this->SetWinampHWND) {
+ this->SetWinampHWND(winampWnd);
+ }
+
+ if(this->GetAudioTypes3) {
+ char name[C_ENCODER_NameLen];
+ fourcc = this->GetAudioTypes3(encoderNum,name);
+ }
+}
+
+C_ENCODER_NSV::~C_ENCODER_NSV() {
+ WaitForSingleObject(hMutex,INFINITE);
+
+ CloseHandle(hMutex);
+ hMutex = NULL;
+ C_ENCODER::~C_ENCODER();
+}
+
+void C_ENCODER_NSV::Close() {
+ C_ENCODER::Close();
+
+ if(encoder)
+ delete encoder;
+ encoder = NULL;
+}
+
+void C_ENCODER_NSV::Reset() {
+ if(WaitForSingleObject(hMutex,INFINITE) != WAIT_OBJECT_0) return;
+
+ Close();
+
+ if(!configfile) {
+ configfile = GetSCIniFile(winampWnd);
+ }
+
+ FillConfFile(configfile);
+
+ int nch = ((T_ENCODER_NSV_INFO*)ExtendedInfoPtr)->input_numChannels;
+ int srate = ((T_ENCODER_NSV_INFO*)ExtendedInfoPtr)->input_sampleRate;
+ if (CreateAudio3) {
+ const int bps = 16; /* I think this is always the case. */
+ encoder = CreateAudio3(nch,srate,bps,mmioFOURCC('P','C','M',' '),&fourcc,configfile);
+ }
+ else encoder = NULL;
+
+ /* I think (in that I havn't found anything to the contrary) that in the CreateAudio3 call, the encoder
+ * reads all its settings from the conf_file and never touches them again. Hence, this is safe. Ahem.
+ */
+ FillAttribs();
+ ReleaseMutex(hMutex);
+}
+
+int C_ENCODER_NSV::Encode(const void *inputbuf, const unsigned int inputbufsize, void *outputbuf, const unsigned int outputbufsize, int *inputamtused) {
+
+ if(WaitForSingleObject(hMutex,INFINITE) != WAIT_OBJECT_0) return 0;
+ int ret=0;
+ if(encoder && (inputbuf != NULL) && (outputbuf != NULL) && (inputbufsize != 0) && (outputbufsize != 0) && (inputamtused != NULL)) {
+ ret = encoder->Encode(0,(void *)inputbuf,inputbufsize,inputamtused,outputbuf,outputbufsize);
+ } else
+ *inputamtused = inputbufsize; /* we havn't got the dll, so just say everything is ok? */
+
+ ReleaseMutex(hMutex);
+ return ret;
+}
+
+static BOOL CALLBACK configure_dlgproc(HWND intDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) {
+
+ switch(uMsg) {
+ case WM_INITDIALOG:
+ if(configfourcc == mmioFOURCC('A','D','T','S')) {
+ SetWindowTextW(intDlg, LocalisedString(IDS_FHGAAC_ENCODER, NULL, 0));
+ }
+ #ifdef USE_OGG
+ else if(configfourcc == mmioFOURCC('O','G','G',' ')) {
+ SetWindowTextW(intDlg, LocalisedString(IDS_OGG_CONFIG_TITLE, NULL, 0));
+ }
+ #endif
+
+ cfgwnd=ConfigAudio3(intDlg, encoderDllInstance, configfourcc, configfile);
+
+ if(cfgwnd) {
+ RECT r;
+ GetWindowRect(GetDlgItem(intDlg,IDC_GO_HERE),&r);
+ ScreenToClient(intDlg,(LPPOINT)&r);
+ SetWindowPos(cfgwnd,NULL,r.left,r.top,0,0,SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER);
+ ShowWindow(cfgwnd,SW_SHOWNA);
+ InvalidateRect(intDlg,NULL,FALSE);
+ }
+ break;
+ case WM_COMMAND:
+ if(LOWORD(wParam) == IDCANCEL) EndDialog(intDlg,0);
+ break;
+ case WM_DESTROY:
+ DestroyWindow(cfgwnd);
+ break;
+ }
+ return 0;
+}
+
+void C_ENCODER_NSV::Configure(HWND parent, HINSTANCE hDllInstance) {
+ if(ConfigAudio3) {
+ configfourcc = fourcc;
+ if(!configfile) {
+ configfile = GetSCIniFile(winampWnd);
+ }
+
+ ::ConfigAudio3 = this->ConfigAudio3;
+ ::encoderDllInstance = GetEncoderInstance();
+
+ if(WaitForSingleObject(hMutex,INFINITE) != WAIT_OBJECT_0) return;
+ FillConfFile(configfile);
+ ReleaseMutex(hMutex);
+
+ LocalisedDialogBox(hDllInstance,IDD_NSVCONFIG,parent,::configure_dlgproc);
+
+ if(WaitForSingleObject(hMutex,INFINITE) != WAIT_OBJECT_0) return;
+ ReadConfFile(configfile);
+ Reset();
+ ReleaseMutex(hMutex);
+ }
+} \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_nsv.h b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_nsv.h
new file mode 100644
index 00000000..14adca08
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_nsv.h
@@ -0,0 +1,76 @@
+/* This is an abstract class to use the NSV style of encoder.
+ */
+
+#ifndef __C_ENCODER_NSV_H__
+#define __C_ENCODER_NSV_H__
+
+#include "c_encoder.h"
+#include "enc_if.h"
+#include <windows.h>
+#include <Shlobj.h>
+#include "../../Resource/resource.h"
+
+struct T_ENCODER_NSV_INFO {
+ unsigned int output_bitRate;
+ unsigned int input_numChannels;
+ unsigned int input_sampleRate;
+};
+
+class C_ENCODER_NSV : public C_ENCODER {
+private:
+ HANDLE hMutex;
+protected:
+ // These are exported by enc_*.dll
+ AudioCoder* (*CreateAudio3)(int nch, int srate, int bps, unsigned int srct, unsigned int *outt, char *configfile);
+ int (*GetAudioTypes3)(int idx, char *desc);
+ HWND (*ConfigAudio3)(HWND hwndParent, HINSTANCE hinst, unsigned int outt, char *configfile);
+ void (*SetWinampHWND)(HWND hwnd);
+ int (*SetConfigItem)(unsigned int outt, char *item, char *data, char *configfile);
+ int (*GetConfigItem)(unsigned int outt, char *item, char *data, int len, char *configfile);
+ /* We don't need the rest of the exports
+ AudioCoder *(*FinishAudio3)(char *fn, AudioCoder *c);
+ void (*PrepareToFinish)(const char *filename, AudioCoder *coder);
+ */
+
+ // our encoder (the AudioCoder class is defined in enc_if.h)
+ AudioCoder* encoder;
+
+ // the type of the output format
+ unsigned int fourcc;
+
+ // fill up the attribute list (using AddAttrib)
+ virtual void FillAttribs()=0;
+
+ // child classes MUST call this in their constructor
+ // note: encoderNum defaults to 0 which resolves to the first encoder
+ // in most enc_* but make sure to set this correctly for others
+ virtual void SetEncoder(void * CreateAudio3, void * GetAudioTypes3, void * ConfigAudio3, void * SetWinampHWND, int encoderNum=0);
+
+ // this is used in Configure()
+ virtual HINSTANCE GetEncoderInstance()=0;
+
+ // this is used for esternal encoders so they can be correctly localised
+ HWND winampWnd;
+
+public:
+ C_ENCODER_NSV(int ExtInfoSize = sizeof(T_ENCODER_NSV_INFO));
+ virtual ~C_ENCODER_NSV();
+
+ virtual void Close();
+ virtual void Reset();
+
+ virtual int Encode(const void *inputbuf, const unsigned int inputbufsize, void *outputbuf, const unsigned int outputbufsize, int *inputamtused); /* all values are in BYTES! */
+
+ // show configuration dialog
+ virtual void Configure(HWND parent,HINSTANCE hDllInstance);
+
+ virtual bool UseNsvConfig() { return true; };
+
+ // populate the configuration file with current settings
+ virtual void FillConfFile(char * conf_file, char * section=NULL)=0;
+
+ // read the configuration file and change current settings
+ virtual void ReadConfFile(char * conf_file, char * section=NULL)=0;
+};
+
+#endif /* !__C_ENCODER_NSV_H__ */ \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_ogg.cpp b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_ogg.cpp
new file mode 100644
index 00000000..e9420b7b
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_ogg.cpp
@@ -0,0 +1,117 @@
+#include "c_encoder_ogg.h"
+#include "../../utils.h"
+
+HINSTANCE C_ENCODER_OGG::hEncoderInstance = NULL;
+
+C_ENCODER_OGG::C_ENCODER_OGG(HWND winamp) : C_ENCODER_NSV(sizeof(T_ENCODER_OGG_INFO)) {
+ SetName("OGG Vorbis Encoder");
+ winampWnd = winamp;
+ ConfigAudio3 = NULL;
+ if(hEncoderInstance == NULL) {
+ wchar_t dir[MAX_PATH] = {0};
+ snwprintf(dir, MAX_PATH, L"%s\\enc_vorbis.dll", GetPluginDirectoryW(winamp));
+ hEncoderInstance = LoadLibraryW(dir);
+ }
+
+ if(hEncoderInstance) {
+ void * CreateAudio3=(void *)GetProcAddress(hEncoderInstance, "CreateAudio3");
+ void * GetAudioTypes3=(void *)GetProcAddress(hEncoderInstance, "GetAudioTypes3");
+ void * ConfigAudio3=(void *)GetProcAddress(hEncoderInstance, "ConfigAudio3");
+ void * SetWinampHWND=(void *)GetProcAddress(hEncoderInstance, "SetWinampHWND");
+ SetEncoder(CreateAudio3,GetAudioTypes3,ConfigAudio3,SetWinampHWND);
+ }
+
+ T_ENCODER_OGG_INFO * EncInfo = (T_ENCODER_OGG_INFO *)ExtendedInfoPtr;
+ EncInfo->output_bitRate = OGG_DEFAULT_OUTPUTBITRATE;
+ EncInfo->output_channelmode = OGG_DEFAULT_OUTPUTMODE;
+ EncInfo->output_samplerate = OGG_DEFAULT_OUTPUTSAMPLERATE;
+}
+
+C_ENCODER_OGG::~C_ENCODER_OGG() {
+ C_ENCODER_NSV::~C_ENCODER_NSV();
+}
+
+static int cacheVal=0;
+bool C_ENCODER_OGG::isPresent(HWND winamp) {
+ if(cacheVal!=0 && hEncoderInstance!=0) return cacheVal==2;
+ bool ret=false;
+ wchar_t dir[MAX_PATH] = {0};
+ snwprintf(dir, MAX_PATH, L"%s\\enc_vorbis.dll", GetPluginDirectoryW(winamp));
+ FILE * f = _wfopen(dir, L"rb");
+ if (f) {
+ fseek(f,0,2);
+ if(ftell(f) > 0) ret=true;
+ fclose(f);
+ }
+ cacheVal=ret?2:1;
+ return ret;
+}
+
+void C_ENCODER_OGG::FillAttribs() {
+ T_ENCODER_OGG_INFO &EncInfo = *(T_ENCODER_OGG_INFO *)ExtendedInfoPtr;
+ T_ENCODER_OGG_INFO *attribs = new T_ENCODER_OGG_INFO;
+ *attribs = EncInfo;
+ AddAttrib("",attribs);
+}
+
+void C_ENCODER_OGG::FillConfFile(char * conf_file, char * section) {
+ if(!section) section="audio_ogg";
+
+ T_ENCODER_OGG_INFO &EncInfo = *(T_ENCODER_OGG_INFO *)ExtendedInfoPtr;
+ configtype * cfg = new configtype;
+ cfg->cfg_abr_use_max=0;
+ cfg->cfg_abr_use_min=0;
+ cfg->cfg_mode=0; //VBR
+ cfg->cfg_vbrquality=EncInfo.output_quality;
+ cfg->cfg_abr_nominal=EncInfo.output_bitRate;
+ cfg->cfg_abr_max=EncInfo.output_bitRate;
+ cfg->cfg_abr_min=EncInfo.output_bitRate;
+
+ if (conf_file) WritePrivateProfileStruct(section,"conf",cfg,sizeof(configtype),conf_file);
+}
+int setBitrate(float ql)
+{
+ int br = 64;
+ //ql = ql*10;
+ // jkey: this is a pain in the ass,but the only
+ // way i can figure out how to get the bitrate
+ // outside of enc_vorbis.
+ // Also quality enforcement is needed to prevent the
+ // yp filling up with non standard bitrate streams.
+ // although this is vbr and will be variable bitrate anyway.
+ if(ql == 10 || (ql < 10 && ql > 9.5)){br=500;ql = 10.0f; return br;}
+ if(ql == 9.0f || (ql < 10.0f && ql > 9.0f)){br=320;ql = 9.0f;return br;}
+ if(ql == 8.0f || (ql < 9.0f && ql > 8.0f)){br=256;ql = 8.0f;return br;}
+ if(ql == 7.0f || (ql < 8.0f && ql > 7.0f)){br=224;ql = 7.0f;return br;}
+ if(ql == 6.0f || (ql < 7.0f && ql > 6.0f)){br=192;ql = 6.0f;return br;}
+ if(ql == 5.0f || (ql < 6.0f && ql > 5.0f)){br=160;ql = 5.0f;return br;}
+ if(ql == 4.0f || (ql < 5.0f && ql > 4.0f)){br=128;ql = 4.0f;return br;}
+ if(ql == 3.0f || (ql < 4.0f && ql > 3.0f)){br=112;ql = 3.0f;return br;}
+ if(ql == 2.0f || (ql < 3.0f && ql > 2.0f)){br=96;ql = 2.0f;return br;}
+ if(ql == 1.0f || (ql < 2.0f && ql > 1.0f)){br=80;ql = 1.0f;return br;}
+ if(ql == 0.0f || (ql < 1.0f && ql > 0.0f)){ br=64;ql = 0.0f;return br;}
+ if(ql == -0.5f || (ql < 0.0f && ql > -0.5f)){br=56;ql = -0.5f;return br;}
+ if(ql == -1.0f || ql < -0.5f){br=48;ql = -1.0f;return br;}
+ return br;
+}
+void C_ENCODER_OGG::ReadConfFile(char * conf_file, char * section) {
+ if(!section) section="audio_ogg";
+ T_ENCODER_OGG_INFO &EncInfo = *(T_ENCODER_OGG_INFO *)ExtendedInfoPtr;
+ T_ENCODER_OGG_INFO *attribs = new T_ENCODER_OGG_INFO;
+ *attribs = EncInfo;
+ configtype * cfg = new configtype;
+ cfg->cfg_abr_use_max=0;
+ cfg->cfg_abr_use_min=0;
+ cfg->cfg_mode=0; //VBR
+ cfg->cfg_vbrquality=0.0f;
+ cfg->cfg_abr_nominal=64;
+ cfg->cfg_abr_max=352;
+ cfg->cfg_abr_min=32;
+
+ if (conf_file) GetPrivateProfileStruct(section,"conf",cfg,sizeof(configtype),conf_file);
+ attribs->output_samplerate = OGG_DEFAULT_OUTPUTSAMPLERATE;
+ attribs->output_channelmode = cfg->cfg_mode;
+ attribs->output_quality = cfg->cfg_vbrquality;
+ attribs->output_bitRate = setBitrate(attribs->output_quality*10);
+ ChangeSettings(attribs);
+} \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_ogg.h b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_ogg.h
new file mode 100644
index 00000000..be20d689
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/c_encoder_ogg.h
@@ -0,0 +1,47 @@
+#ifndef __C_ENCODER_OGG_H__
+#define __C_ENCODER_OGG_H__
+
+#include "c_encoder_nsv.h"
+//#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
+
+typedef struct
+{
+ bool cfg_abr_use_max,cfg_abr_use_min;
+ UINT cfg_mode;
+
+ float cfg_vbrquality;
+ UINT cfg_abr_nominal;
+ UINT cfg_abr_max;
+ UINT cfg_abr_min;
+} configtype;
+
+struct T_ENCODER_OGG_INFO : public T_ENCODER_NSV_INFO
+{
+ float output_quality;
+ unsigned int output_samplerate;
+ unsigned int output_channelmode;
+};
+
+#define OGG_DEFAULT_OUTPUTMODE 0
+#define OGG_DEFAULT_OUTPUTBITRATE 192
+#define OGG_DEFAULT_OUTPUTSAMPLERATE 44100
+#define OGG_DEFAULT_OUTPUTQUALITY 2.0f
+
+class C_ENCODER_OGG : public C_ENCODER_NSV {
+private:
+ HWND winamp;
+protected:
+ virtual void FillAttribs();
+public:
+ static HINSTANCE hEncoderInstance;
+ C_ENCODER_OGG(HWND hwnd = 0);
+ virtual ~C_ENCODER_OGG();
+ static bool isPresent(HWND winamp);
+ virtual void ReadConfFile(char * conf_file, char * section=NULL);
+ virtual void FillConfFile(char * conf_file, char * section=NULL);
+ static void Unload() { if(hEncoderInstance) FreeLibrary(hEncoderInstance); hEncoderInstance=0; }
+ virtual char * GetContentType() { return "audio/ogg"; }
+ virtual HINSTANCE GetEncoderInstance() { return hEncoderInstance; }
+};
+
+#endif /* !__C_ENCODER_OGG_H__ */ \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/enc_if.h b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/enc_if.h
new file mode 100644
index 00000000..70eaff30
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/Encoders/enc_if.h
@@ -0,0 +1,44 @@
+/*
+** enc_if.h - common encoder interface
+**
+** Copyright (C) 2001-2003 Nullsoft, Inc.
+**
+** This software is provided 'as-is', without any express or implied warranty.
+** In no event will the authors be held liable for any damages arising from the use of this software.
+**
+** Permission is granted to anyone to use this software for any purpose, including commercial
+** applications, and to alter it and redistribute it freely, subject to the following restrictions:
+** 1. The origin of this software must not be misrepresented; you must not claim that you wrote the
+** original software. If you use this software in a product, an acknowledgment in the product
+** documentation would be appreciated but is not required.
+** 2. Altered source versions must be plainly marked as such, and must not be misrepresented as
+** being the original software.
+** 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef _NSV_ENC_IF_H_
+#define _NSV_ENC_IF_H_
+class VideoCoder
+{
+ public:
+ VideoCoder() { }
+ virtual int Encode(void *in, void *out, int *iskf)=0; // returns bytes in out
+ virtual ~VideoCoder() { };
+};
+
+class AudioCoder
+{
+ public:
+ AudioCoder() { }
+ virtual int Encode(int framepos, void *in, int in_avail, int *in_used, void *out, int out_avail)=0; //returns bytes in out
+ virtual ~AudioCoder() { };
+};
+
+// unsigned int GetAudioTypes3(int idx, char *desc);
+// unsigned int GetVideoTypes3(int idx, char *desc);
+// AudioCoder *CreateAudio3(int nch, int srate, int bps, unsigned int srct, unsigned int *outt, char *configfile);
+// VideoCoder *CreateVideo3(int w, int h, double frt, unsigned int pixt, unsigned int *outt, char *configfile);
+// HWND ConfigAudio3(HWND hwndParent, HINSTANCE hinst, unsigned int outt, char *configfile);
+// HWND ConfigVideo3(HWND hwndParent, HINSTANCE hinst, unsigned int outt, char *configfile);
+
+#endif //_NSV_ENC_IF_H_ \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/Include/c_jobmanager.h b/Src/Plugins/DSP/dsp_sc/sc2srclib/Include/c_jobmanager.h
new file mode 100644
index 00000000..c7feacc9
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/Include/c_jobmanager.h
@@ -0,0 +1,254 @@
+#ifndef __C_JOBMANAGER_H__
+#define __C_JOBMANAGER_H__
+
+#include <vector>
+
+#ifdef _WIN32
+#include <wtypes.h>
+#include <winbase.h> // for mutex support
+#define T_MUTEX HANDLE
+#else // _WIN32
+#error "This won't compile under anything other than windows since I haven't implemented mutexing on anything else"
+#endif // _WIN32
+
+template<class T> class C_JOBMANAGER {
+public:
+ typedef int (*T_JOBHANDLER)(int state, int last_state, T *userData);
+private:
+ struct T_JOB {
+ int state;
+ int last_state;
+ int suspended;
+ T *userData;
+ };
+ struct T_HANDLER {
+ int state;
+ int last_state;
+ T_JOBHANDLER jobHandler;
+ };
+ std::vector<T_JOB*> JobList;
+ std::vector<T_HANDLER*> HandlerList;
+ T_MUTEX mutex;
+
+protected:
+ int waitForMutex() {
+#ifdef _WIN32
+ if(WaitForSingleObject(mutex,INFINITE) == WAIT_OBJECT_0) return 1;
+#else // _WIN32
+ // insert mutex magic here
+#endif // _WIN32
+ return 0;
+ }
+
+ void releaseMutex() {
+#ifdef _WIN32
+ ReleaseMutex(mutex);
+#else // _WIN32
+ // insert mutex magic here
+#endif // _WIN32
+ }
+
+public:
+ C_JOBMANAGER() {
+#ifdef _WIN32
+ mutex = CreateMutex(NULL,TRUE,NULL);
+ ReleaseMutex(mutex);
+#else // _WIN32
+ // insert mutex magic here
+#endif // _WIN32
+ }
+
+ virtual ~C_JOBMANAGER() {
+ waitForMutex();
+#ifdef _WIN32
+ CloseHandle(mutex);
+ mutex = NULL;
+#else // _WIN32
+ // insert mutex magic here
+#endif // _WIN32
+
+ //JobList.deleteAll();
+ for (auto job : JobList)
+ {
+ delete job;
+ }
+ JobList.clear();
+
+ //HandlerList.deleteAll();
+ for (auto handler : HandlerList)
+ {
+ delete handler;
+ }
+ HandlerList.clear();
+ }
+
+ T *operator[](int job) {
+ if(!waitForMutex()) return NULL;
+ T_JOB *j = JobList[job];
+ T *val = NULL;
+ if(j) val = j->userData;
+ releaseMutex();
+ return val;
+ }
+
+ virtual int AddJob(int state, T *userData, int suspended = 0, int isUserUnique = 1) {
+ if(!waitForMutex()) return -1;
+ int n = JobList.size();
+ if(isUserUnique && n) {
+ for(int i = n-1; i >= 0; i--) {
+ T_JOB *item = JobList[i];
+ if(item) {
+ if(item->userData == userData) {
+ releaseMutex();
+ return -1;
+ }
+ }
+ }
+ }
+ T_JOB *job = new T_JOB;
+ job->last_state = OUT_DISCONNECTED;
+ job->state = state;
+ job->suspended = suspended;
+ job->userData = userData;
+ JobList.push_back(job);
+ releaseMutex();
+ return n;
+ }
+
+ virtual int GetJobState(int job) {
+ int retval = -1;
+ if(waitForMutex()) {
+ int n = JobList.size();
+ if(job < n && job >= 0) retval = JobList[job]->state;
+ releaseMutex();
+ }
+ return retval;
+ }
+
+ virtual void SetJobState(int job, int state) {
+ if(!waitForMutex()) return;
+ int n = JobList.size();
+ if(job < n && job >= 0) JobList[job]->state = state;
+ releaseMutex();
+ }
+
+ virtual void SuspendJob(int job, int suspended) {
+ if(!waitForMutex()) return;
+ int n = JobList.size();
+ if(job < n && job >= 0) JobList[job]->suspended = suspended;
+ releaseMutex();
+ }
+
+ virtual void DelJob(int job) {
+ if(!waitForMutex()) return;
+ int n = JobList.size();
+ if(job < n && job >= 0) {
+ delete JobList[job];
+ JobList.erase(JobList.begin() + job);
+ }
+ releaseMutex();
+ }
+
+ virtual void ClearJobs() {
+ if(!waitForMutex())
+ return;
+
+ //JobList.deleteAll();
+ for (auto job : JobList)
+ {
+ delete job;
+ }
+ JobList.clear();
+
+ releaseMutex();
+ }
+
+ virtual void AddHandler(int state, T_JOBHANDLER jobHandler) {
+ if(!waitForMutex()) return;
+ int n = HandlerList.size();
+ for(int i = n-1; i >= 0; i--) {
+ T_HANDLER *item = HandlerList[i];
+ if(item) {
+ if(item->state == state) {
+ releaseMutex();
+ return;
+ }
+ }
+ }
+ T_HANDLER *handler = new T_HANDLER;
+ handler->state = state;
+ handler->jobHandler = jobHandler;
+ HandlerList.push_back(handler);
+ releaseMutex();
+ }
+
+ virtual void DelHandler(int state) {
+ if(!waitForMutex()) return;
+ int n = HandlerList.size();
+ for(int i = n-1; i >= 0; i--) {
+ T_HANDLER *item = HandlerList[i];
+ if(item) {
+ if(item->state == state) {
+ delete HandlerList[i];
+ HandlerList.erase(HandlerList.begin() + i);
+ releaseMutex();
+ return;
+ }
+ }
+ }
+ releaseMutex();
+ }
+
+ virtual void ClearHandlers() {
+ if(!waitForMutex())
+ return;
+
+ //HandlerList.deleteAll();
+ for (auto handler : HandlerList)
+ {
+ delete handler;
+ }
+ HandlerList.clear();
+
+ releaseMutex();
+ }
+
+ virtual int GetNumJobs() {
+ if(!waitForMutex()) return -1;
+ int n = JobList.size();
+ releaseMutex();
+ return n;
+ }
+
+ virtual int GetNumHandlers() {
+ if(!waitForMutex()) return -1;
+ int n = HandlerList.size();
+ releaseMutex();
+ return n;
+ }
+
+ virtual void Run(int job) {
+ if(!waitForMutex()) return;
+ int nJ = JobList.size();
+ int nH = HandlerList.size();
+ if(job < nJ && job >= 0) {
+ T_JOB *job_item = JobList[job];
+ for(int i = nH-1; i >= 0; i--) {
+ T_HANDLER *handler = HandlerList[i];
+ if(handler) {
+ if(handler->state == job_item->state) {
+ if(!job_item->suspended) {
+ int cur_state = job_item->state;
+ job_item->state = handler->jobHandler(job_item->state,job_item->last_state,job_item->userData);
+ job_item->last_state = cur_state;
+ }
+ break;
+ }
+ }
+ }
+ }
+ releaseMutex();
+ }
+};
+
+#endif // !__C_JOBMANAGER_H__ \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/Include/c_serial_jobmanager.h b/Src/Plugins/DSP/dsp_sc/sc2srclib/Include/c_serial_jobmanager.h
new file mode 100644
index 00000000..6023dd01
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/Include/c_serial_jobmanager.h
@@ -0,0 +1,24 @@
+#ifndef __C_SERIAL_JOBMANAGER_H__
+#define __C_SERIAL_JOBMANAGER_H__
+
+#include "c_jobmanager.h"
+
+template<class T> class C_SERIAL_JOBMANAGER : public C_JOBMANAGER<T> {
+private:
+ int currentJob;
+public:
+ C_SERIAL_JOBMANAGER() {
+ currentJob = 0;
+ }
+ ~C_SERIAL_JOBMANAGER() { }
+ int GetCurrentJob() { return currentJob; }
+ virtual void Run(int passes = 1) {
+ int numPasses = passes;
+ while(numPasses-- > 0) {
+ C_JOBMANAGER<T>::Run(currentJob++);
+ if(currentJob > GetNumJobs()) currentJob = 0;
+ }
+ }
+};
+
+#endif // !__C_SERIAL_JOBMANAGER_H__ \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/Include/c_shoutcast_2_output.h b/Src/Plugins/DSP/dsp_sc/sc2srclib/Include/c_shoutcast_2_output.h
new file mode 100644
index 00000000..5b074de0
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/Include/c_shoutcast_2_output.h
@@ -0,0 +1,194 @@
+#ifndef __C_SHOUTCAST_2_OUTPUT_H__
+#define __C_SHOUTCAST_2_OUTPUT_H__
+
+#include <time.h>
+#include <string>
+#include <stdio.h>
+#include <stdlib.h>
+#include "c_serial_jobmanager.h"
+#include "../jnetlib/jnetlib.h"
+#include "../Encoders/c_encoder.h"
+#include "../Encoders/c_encoder_mp3dll.h"
+
+#include "../lame/include/lame.h"
+#include "../lame/libmp3lame/lame_global_flags.h"
+#include "../uvAuth21/uvAuth21.h"
+
+#ifdef USEAACP
+#include "../Encoders/c_encoder_aacp.h"
+#endif
+struct T_OUTPUT_CONFIG {
+ char Name[32];
+ char UserID[256];
+ char Address[1024];
+ u_short Port;
+ char StationID[8];
+ char Password[256]; // 4 - 8 for 1.8.2
+ char cipherkey[32];// sc2 cipherkey
+ int AutoRecon;
+ int ReconTime;
+ char Description[1024];
+ char ServerURL[2048];
+ int Genre1;
+ int Genre2;
+ char Genre3[1024];
+ char ICQ[128];
+ char AIM[512];
+ char IRC[512];
+ char content_type[11];
+ int Public;
+ int doTitleUpdate;
+ int protocol;
+ int DoUpload;
+ char introfilepath[4096];
+ char backupfile[4096];
+};
+
+#define DEFAULT_ENCODER (C_ENCODER *)(-1)
+
+#define OM_ENCODE 1
+#define OM_OUTPUT 2
+#define OM_OTHER 4
+#define OM_ALL (OM_ENCODE | OM_OUTPUT | OM_OTHER)
+
+enum OUTPUTTYPE {
+ OUTTYPE_SOURCE,
+ OUTTYPE_TITLE,
+};
+
+struct T_OUTPUT_INFO {
+ unsigned int BytesSent; // how many bytes of content we've sent
+ clock_t ConnectionTime; // time a socket connection occurred
+ int Version; // server version
+ int Caps; // server capabilities
+ int Reconnect; // flag for the reconnection algorithm
+ int ReconnectTime; // value used in conjunction with the reconnection algorithm
+ int Succeeded; // had at least one successful connection (for reconnection alg.) -1 = password failure
+ int sc2Suceeded;//sc2 version
+ char ErrorMsg[1024];
+ time_t ConnectedAt;
+ wchar_t Title[1024];
+ wchar_t Next[1024];
+ char URL[1024];
+ int introuploaded;
+ int backupuploaded;
+};
+
+struct T_OUTPUT {
+ JNL_Connection Output;
+ enum OUTPUTTYPE Type;
+ int Bitrate; // this shouldn't be here, but it's the only way we can tell the shoutcast server the bitrate
+ char * ContentType; //neither should this
+ int SlowClose; // set to 1 to wait until all data is sent before closing the connection
+ T_OUTPUT_CONFIG *Config;
+ T_OUTPUT_INFO Info;
+ int m_sendmetadata;
+ int m_initdone;
+};
+
+enum OUTPUTSTATE {
+ OUT_ERROR, // not a true state, but is returned when GetState() is called with an invalid connection handle
+ OUT_IDLE,
+ OUT_CONNECT,
+ OUT_REQUEST_CIPHER,
+ OUT_RECV_CIPHER,
+ OUT_SENDAUTH,
+ OUT_RECVAUTHRESPONSE,
+ OUT_SEND_MIME,
+ OUT_RECV_MIME,
+ OUT_SEND_BITRATE,
+ OUT_RECV_BITRATE,
+ OUT_SEND_BUFSIZE,
+ OUT_RECV_BUFSIZE,
+ OUT_SEND_MAX,
+ OUT_RECV_MAX,
+ OUT_SENDYP,
+ OUT_RECVYP,
+ OUT_SEND_INITFLUSH,
+ OUT_RECV_INITFLUSH,
+ OUT_SEND_INITSTANDBY,
+ OUT_RECV_INITSTANDBY,
+ OUT_SEND_INTRO,
+ OUT_RECV_INTRO,
+ OUT_SEND_BACKUP,
+ OUT_RECV_BACKUP,
+ OUT_SENDCONTENT,
+ OUT_DISCONNECT,
+ OUT_RECONNECT,
+ OUT_TITLESENDUPDATE,
+};
+#define OUT_DISCONNECTED OUT_IDLE
+
+class C_SHOUTCAST_2_OUTPUT {
+private:
+ C_ENCODER *Encoder;
+ int IOwnEncoder;
+ C_SERIAL_JOBMANAGER<T_OUTPUT> OutputManager;
+ HANDLE mutex;
+
+protected:
+ static int Output_Idle(int state, T_OUTPUT *userData);
+ static int Output_Connect(int state, T_OUTPUT *userData);
+ static int Output_Request_Cipher(int state, T_OUTPUT *userData);
+ static int Output_Receive_Cipher(int state, T_OUTPUT *userData);
+ static int Output_SendAuth(int state, T_OUTPUT *userData);
+ static int Output_RecvAuthResponse(int state, T_OUTPUT *userData);
+ static int Output_Send_Mime(int state, T_OUTPUT *userData);
+ static int Output_Recv_Mime(int state, T_OUTPUT *userData);
+ static int Output_Send_Bitrate(int state, T_OUTPUT *userData);
+ static int Output_Recv_Bitrate(int state, T_OUTPUT *userData);
+ static int Output_Send_Buf_Size(int state, T_OUTPUT *userData);
+ static int Output_Recv_Buf_Size(int state, T_OUTPUT *userData);
+ static int Output_Send_Max_Size(int state, T_OUTPUT *userData);
+ static int Output_Recv_Max_Size(int state, T_OUTPUT *userData);
+ static int Output_DUMMY(int state, T_OUTPUT *userData);
+ static int Output_SendYP(int state, T_OUTPUT *userData);
+ static int Output_RecvYP(int state, T_OUTPUT *userData);
+ static int Output_Send_InitFlush(int state, T_OUTPUT *userData);
+ static int Output_Recv_InitFlush(int state, T_OUTPUT *userData);
+ static int Output_Send_InitStandby(int state, T_OUTPUT *userData);
+ static int Output_Recv_InitStandby(int state, T_OUTPUT *userData);
+ static int Output_Send_InitMeta(int state, T_OUTPUT *userData);
+ static int Output_Recv_InitMeta(int state, T_OUTPUT *userData);
+ static int Output_Send_Intro(int state, T_OUTPUT *userData);
+ static int Output_Recv_Intro(int state, T_OUTPUT *userData);
+ static int Output_Send_Backup(int state, T_OUTPUT *userData);
+ static int Output_Recv_Backup(int state, T_OUTPUT *userData);
+
+ static int Output_SendContent(int state, T_OUTPUT *userData);
+ static int Output_Disconnect(int state, T_OUTPUT *userData);
+ static int Output_Reconnect(int state, T_OUTPUT *userData);
+ static int Output_Title_SendUpdate(int state, T_OUTPUT *userData);
+ static int Output_Title_SendUpdatev2(int state, T_OUTPUT *userData);
+ // uvox21
+ static char * createUvoxFrameClasstype(std::string typeString);
+ static int createUvoxFrame(int length, char * payload_in,char * payload_out, char * classtype);
+ static int parseUvoxFrame(char * payload_in,char * payload_out);
+ static int checkUvoxFrameForError(char * pload_out,int state, T_OUTPUT *userData);
+
+ void (*lame_init)(void);
+ void (*lame_init_params)(lame_global_flags *);
+ int (*lame_encode_buffer_interleaved)(lame_global_flags *,short int pcm[],int num_samples, char *mp3buffer,int mp3buffer_size);
+ int (*lame_encode_flush)(lame_global_flags *,char *mp3buffer, int size);
+
+public:
+ C_SHOUTCAST_2_OUTPUT();
+ void SetLame(void *init, void *params, void *encode, void *finish);
+ ~C_SHOUTCAST_2_OUTPUT();
+ int Run(int mode = 0, void *Input = NULL, int InputSize = 0);
+ int AddOutput(T_OUTPUT_CONFIG *Config);
+ void UpdateOutput(int Connection);
+ void RemoveOutput(int Connection);
+ void ConnectOutput(int Connection);
+ void DisconnectOutput(int Connection, int withReconnect = 0, int reconnectTime = -1); // withReconnect of -1 will use the output config's setting
+ void SetEncoder(C_ENCODER *encoder, int takeOwnership = 0);
+ void UpdateTitle(wchar_t*Title,wchar_t*Next, int Connection,int titleseq);
+ enum OUTPUTSTATE GetState(int Connection);
+ T_OUTPUT_CONFIG *operator[](int Connection);
+ T_OUTPUT_CONFIG *GetOutput(int Connection);
+ C_ENCODER *GetEncoder();
+ T_OUTPUT_INFO *GetOutputInfo(int Connection);
+ int m_titleseq;
+};
+
+#endif // !__C_SHOUTCAST_2_OUTPUT_H__ \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/Include/shoutcast_output.h b/Src/Plugins/DSP/dsp_sc/sc2srclib/Include/shoutcast_output.h
new file mode 100644
index 00000000..c6378473
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/Include/shoutcast_output.h
@@ -0,0 +1,817 @@
+#ifndef __SHOUTCAST_OUTPUT_H__
+#define __SHOUTCAST_OUTPUT_H__
+
+#include <time.h>
+#include <string>
+#include <stdio.h>
+#include <stdlib.h>
+#include <list>
+#include <fstream>
+#include "c_serial_jobmanager.h"
+#include "../Components/wac_network/wac_network_connection_api.h"
+#include <WinSock2.h>
+
+#include "../Encoders/c_encoder.h"
+#include "../Encoders/c_encoder_mp3dll.h"
+
+#include "../lame/include/lame.h"
+#include "../lame/libmp3lame/lame_global_flags.h"
+#include "../uvAuth21/uvAuth21.h"
+
+#define UV_SYNC_BYTE 0x5A
+#define UV_RESERVED 0x00
+#define UV_END 0x00
+#define UV_END_LEN 1
+#define UV_HEADER_LEN 6
+#define UV_META_LEN 6
+#define UV_FRAME_LEN 16384
+#define UV_MAX_DATA_LEN (UV_FRAME_LEN - UV_HEADER_LEN - UV_END_LEN)
+#define UV_MAX_META_LEN (UV_FRAME_LEN - UV_HEADER_LEN - UV_META_LEN - UV_END_LEN)
+#define UV_MAX_META_FRAGMENTS 32
+#define UV_MAX_TOTAL_META_LEN (UV_MAX_META_LEN * UV_MAX_META_FRAGMENTS)
+
+typedef struct {
+ char* name;
+ bool parent;
+ bool children;
+} SCgenres;
+static SCgenres genres[] = {{"Alternative", true, true},
+ {"Adult Alternative", false},
+ {"Britpop", false},
+ {"Classic Alternative", false},
+ {"College", false},
+ {"Dancepunk", false},
+ {"Dream Pop", false},
+ {"Emo", false},
+ {"Goth", false},
+ {"Grunge", false},
+ {"Hardcore", false},
+ {"Indie Pop", false},
+ {"Indie Rock", false},
+ {"Industrial", false},
+ {"LoFi", false},
+ {"Modern Rock", false},
+ {"New Wave", false},
+ {"Noise Pop", false},
+ {"Post Punk", false},
+ {"Power Pop", false},
+ {"Punk", false},
+ {"Ska", false},
+ {"Xtreme", false},
+
+ {"Blues", true, true},
+ {"Acoustic Blues", false},
+ {"Cajun and Zydeco", false},
+ {"Chicago Blues", false},
+ {"Contemporary Blues", false},
+ {"Country Blues", false},
+ {"Delta Blues", false},
+ {"Electric Blues", false},
+
+ {"Classical", true, true},
+ {"Baroque", false},
+ {"Chamber", false},
+ {"Choral", false},
+ {"Classical Period", false},
+ {"Early Classical", false},
+ {"Impressionist", false},
+ {"Modern", false},
+ {"Opera", false},
+ {"Piano", false},
+ {"Romantic", false},
+ {"Symphony", false},
+
+ {"Country", true, true},
+ {"Alt Country", false},
+ {"Americana", false},
+ {"Bluegrass", false},
+ {"Classic Country", false},
+ {"Contemporary Bluegrass", false},
+ {"Contemporary Country", false},
+ {"Honky Tonk", false},
+ {"Hot Country Hits", false},
+ {"Western", false},
+
+ {"Decades", true, true},
+ {"30s", false},
+ {"40s", false},
+ {"50s", false},
+ {"60s", false},
+ {"70s", false},
+ {"80s", false},
+ {"90s", false},
+ {"00s", false},
+
+ {"Easy Listening", true, true},
+ {"Exotica", false},
+ {"Light Rock", false},
+ {"Lounge", false},
+ {"Orchestral Pop", false},
+ {"Polka", false},
+ {"Space Age Pop", false},
+
+ {"Electronic", true, true},
+ {"Acid House", false},
+ {"Ambient", false},
+ {"Big Beat", false},
+ {"Breakbeat", false},
+ {"Dance", false},
+ {"Demo", false},
+ {"Disco", false},
+ {"Downtempo", false},
+ {"Drum and Bass", false},
+ {"Dubstep", false},
+ {"Electro", false},
+ {"Garage", false},
+ {"Hard House", false},
+ {"House", false},
+ {"IDM", false},
+ {"Jungle", false},
+ {"Progressive", false},
+ {"Techno", false},
+ {"Trance", false},
+ {"Tribal", false},
+ {"Trip Hop", false},
+
+ {"Folk", true, true},
+ {"Alternative Folk", false},
+ {"Contemporary Folk", false},
+ {"Folk Rock", false},
+ {"New Acoustic", false},
+ {"Old Time", false},
+ {"Traditional Folk", false},
+ {"World Folk", false},
+
+ {"Inspirational", true, true},
+ {"Christian", false},
+ {"Christian Metal", false},
+ {"Christian Rap", false},
+ {"Christian Rock", false},
+ {"Classic Christian", false},
+ {"Contemporary Gospel", false},
+ {"Gospel", false},
+ {"Praise and Worship", false},
+ {"Sermons and Services", false},
+ {"Southern Gospel", false},
+ {"Traditional Gospel", false},
+
+ {"International", true, true},
+ {"African", false},
+ {"Afrikaans", false},
+ {"Arabic", false},
+ {"Asian", false},
+ {"Bollywood", false},
+ {"Brazilian", false},
+ {"Caribbean", false},
+ {"Celtic", false},
+ {"Creole", false},
+ {"European", false},
+ {"Filipino", false},
+ {"French", false},
+ {"German", false},
+ {"Greek", false},
+ {"Hawaiian and Pacific", false},
+ {"Hebrew", false},
+ {"Hindi", false},
+ {"Indian", false},
+ {"Islamic", false},
+ {"Japanese", false},
+ {"Klezmer", false},
+ {"Korean", false},
+ {"Mediterranean", false},
+ {"Middle Eastern", false},
+ {"North American", false},
+ {"Russian", false},
+ {"Soca", false},
+ {"South American", false},
+ {"Tamil", false},
+ {"Turkish", false},
+ {"Worldbeat", false},
+ {"Zouk", false},
+
+ {"Jazz", true, true},
+ {"Acid Jazz", false},
+ {"Avant Garde", false},
+ {"Big Band", false},
+ {"Bop", false},
+ {"Classic Jazz", false},
+ {"Cool Jazz", false},
+ {"Fusion", false},
+ {"Hard Bop", false},
+ {"Latin Jazz", false},
+ {"Smooth Jazz", false},
+ {"Swing", false},
+ {"Vocal Jazz", false},
+ {"World Fusion", false},
+
+ {"Latin", true, true},
+ {"Bachata", false},
+ {"Banda", false},
+ {"Bossa Nova", false},
+ {"Cumbia", false},
+ {"Flamenco", false},
+ {"Latin Dance", false},
+ {"Latin Pop", false},
+ {"Latin Rap and Hip Hop", false},
+ {"Latin Rock", false},
+ {"Mariachi", false},
+ {"Merengue", false},
+ {"Ranchera", false},
+ {"Reggaeton", false},
+ {"Regional Mexican", false},
+ {"Salsa", false},
+ {"Samba", false},
+ {"Tango", false},
+ {"Tejano", false},
+ {"Tropicalia", false},
+
+ {"Metal", true, true},
+ {"Black Metal", false},
+ {"Classic Metal", false},
+ {"Death Metal", false},
+ {"Extreme Metal", false},
+ {"Grindcore", false},
+ {"Hair Metal", false},
+ {"Heavy Metal", false},
+ {"Metalcore", false},
+ {"Power Metal", false},
+ {"Progressive Metal", false},
+ {"Rap Metal", false},
+ {"Thrash Metal", false},
+
+ {"Misc", true, false},
+
+ {"New Age", true, true},
+ {"Environmental", false},
+ {"Ethnic Fusion", false},
+ {"Healing", false},
+ {"Meditation", false},
+ {"Spiritual", false},
+
+ {"Pop", true, true},
+ {"Adult Contemporary", false},
+ {"Barbershop", false},
+ {"Bubblegum Pop", false},
+ {"Dance Pop", false},
+ {"Idols", false},
+ {"JPOP", false},
+ {"KPOP", false},
+ {"Oldies", false},
+ {"Soft Rock", false},
+ {"Teen Pop", false},
+ {"Top 40", false},
+ {"World Pop", false},
+
+ {"Public Radio", true, true},
+ {"College", false},
+ {"News", false},
+ {"Sports", false},
+ {"Talk", false},
+ {"Weather", false},
+
+ {"R&B and Urban", true, false},
+ {"Classic R&B", false},
+ {"Contemporary R&B", false},
+ {"Doo Wop", false},
+ {"Funk", false},
+ {"Motown", false},
+ {"Neo Soul", false},
+ {"Quiet Storm", false},
+ {"Soul", false},
+ {"Urban Contemporary", false},
+
+ {"Rap", true, true},
+ {"Alternative Rap", false},
+ {"Dirty South", false},
+ {"East Coast Rap", false},
+ {"Freestyle", false},
+ {"Gangsta Rap", false},
+ {"Hip Hop", false},
+ {"Mixtapes", false},
+ {"Old School", false},
+ {"Turntablism", false},
+ {"Underground Hip Hop", false},
+ {"West Coast Rap", false},
+
+ {"Reggae", true, true},
+ {"Contemporary Reggae", false},
+ {"Dancehall", false},
+ {"Dub", false},
+ {"Pop Reggae", false},
+ {"Ragga", false},
+ {"Reggae Roots", false},
+ {"Rock Steady", false},
+
+ {"Rock", true, true},
+ {"Adult Album Alternative", false},
+ {"British Invasion", false},
+ {"Celtic Rock", false},
+ {"Classic Rock", false},
+ {"Garage Rock", false},
+ {"Glam", false},
+ {"Hard Rock", false},
+ {"Jam Bands", false},
+ {"JROCK", false},
+ {"Piano Rock", false},
+ {"Prog Rock", false},
+ {"Psychedelic", false},
+ {"Rock & Roll", false},
+ {"Rockabilly", false},
+ {"Singer and Songwriter", false},
+ {"Surf", false},
+
+ {"Seasonal and Holiday", true, true},
+ {"Anniversary", false},
+ {"Birthday", false},
+ {"Christmas", false},
+ {"Halloween", false},
+ {"Hanukkah", false},
+ {"Honeymoon", false},
+ {"Kwanzaa", false},
+ {"Valentine", false},
+ {"Wedding", false},
+ {"Winter", false},
+
+ {"Soundtracks", true, true},
+ {"Anime", false},
+ {"Kids", false},
+ {"Original Score", false},
+ {"Showtunes", false},
+ {"Video Game Music", false},
+
+ {"Talk", true, true},
+ {"BlogTalk", false},
+ {"Comedy", false},
+ {"Community", false},
+ {"Educational", false},
+ {"Government", false},
+ {"News", false},
+ {"Old Time Radio", false},
+ {"Other Talk", false},
+ {"Political", false},
+ {"Scanner", false},
+ {"Spoken Word", false},
+ {"Sports", false},
+ {"Technology", false},
+
+ {"Themes", true, true},
+ {"Adult", false},
+ {"Best Of", false},
+ {"Chill", false},
+ {"Eclectic", false},
+ {"Experimental", false},
+ {"Female", false},
+ {"Heartache", false},
+ {"Instrumental", false},
+ {"LGBT", false},
+ {"Love and Romance", false},
+ {"Party Mix", false},
+ {"Patriotic", false},
+ {"Rainy Day Mix", false},
+ {"Reality", false},
+ {"Sexy", false},
+ {"Shuffle", false},
+ {"Travel Mix", false},
+ {"Tribute", false},
+ {"Trippy", false},
+ {"Work Mix", false}
+};
+
+// pulled from nmrCommon\intTypes.h
+typedef unsigned char __uint8;
+typedef unsigned short __uint16;
+typedef unsigned int __uint32;
+typedef unsigned long long __uint64;
+
+#pragma pack(push,1)
+
+// this structure should be 16384 bytes in total size
+// and is defined in full size so that we know its ok
+struct uv2xHdr
+{ // uvox2 message
+ __uint8 sync;
+ __uint8 qos;
+ __uint16 msgType;
+ __uint16 msgLen;
+ __uint8 m_data[UV_MAX_DATA_LEN];
+ __uint8 end;
+};
+
+struct uv2xMetadataHdr
+{ /* uvox 2 metadata header */
+ __uint8 sync;
+ __uint8 qos;
+ __uint16 msgType;
+ __uint16 msgLen;
+
+ __uint16 id; /* ID (cookie) identifying a metadata package */
+ __uint16 span; /* Span of messages in the metadata package being assembled */
+ __uint16 index; /* Index of the message in the metadata package being assembled */
+
+ __uint8 m_data[UV_MAX_META_LEN];
+ __uint8 end;
+};
+
+#pragma pack(pop)
+
+#define MSG_AUTH 0x1001
+#define MSG_BROADCAST_SETUP 0x1002
+#define MSG_NEGOTIATE_BUFFER_SIZE 0x1003
+#define MSG_STANDBY 0x1004
+#define MSG_TERMINATE 0x1005
+#define MSG_FLUSH_CACHED_METADATA 0x1006
+#define MSG_LISTENER_AUTHENTICATION 0x1007
+#define MSG_MAX_PAYLOAD_SIZE 0x1008
+#define MSG_CIPHER 0x1009
+#define MSG_MIME_TYPE 0x1040
+#define MSG_FILE_TRANSFER_BEGIN 0x1050
+#define MSG_FILE_TRANSFER_DATA 0x1051
+
+#define MSG_BROADCAST_INTERRUPTION 0x2001
+#define MSG_BROADCAST_TERMINATE 0x2002
+
+#define MSG_ICYNAME 0x1100
+#define MSG_ICYGENRE 0x1101
+#define MSG_ICYURL 0x1102
+#define MSG_ICYPUB 0x1103
+
+#define MSG_METADATA_CONTENTINFO 0x3000
+#define MSG_METADATA_URL 0x3001
+#define MSG_METADATA_XML 0x3901
+#define MSG_METADATA_XML_NEW 0x3902
+
+// only id the start of the album art type as it's variable
+#define MSG_METADATA_ALBUMART 0x4000
+#define MSG_METADATA_STATION_ART 0x0000
+#define MSG_METADATA_PLAYING_ART 0x0100
+/*
+ 0x4 0x0xx Station logo
+ 0x4 0x1xx Album art
+
+ 00 = image/jpeg
+ 01 = image/png
+ 02 = image/bmp
+ 03 = image/gif
+*/
+
+#define MSG_METADATA_TIMEREMAINING 0x5001
+
+#define MP3_DATA 0x7000
+#define VLB_DATA 0x8000
+#define AAC_LC_DATA 0x8001
+#define AACP_DATA 0x8003
+#define OGG_DATA 0x8004
+
+struct T_OUTPUT_CONFIG {
+ char Name[32];
+ wchar_t DisplayName[32];
+ char UserID[256];
+ char Address[1024];
+ u_short Port;
+ char StationID[12];
+ char Password[256]; // 4 - 8 for 1.8.2
+ char cipherkey[64]; // sc2 cipherkey
+ int AutoRecon;
+ int ReconTime;
+ char Description[1024];
+ char ServerURL[2048];
+ char Genre[256];
+ char ICQ[128];
+ char AIM[1024];
+ char IRC[1024];
+ int Public;
+ int doTitleUpdate;
+ int protocol;
+ int protocol_retry;
+ char Now[1024];
+ char Next[1024];
+};
+
+#define DEFAULT_ENCODER (C_ENCODER *)(-1)
+
+#define OM_ENCODE 1
+#define OM_OUTPUT 2
+#define OM_OTHER 4
+#define OM_ALL (OM_ENCODE | OM_OUTPUT | OM_OTHER)
+
+enum OUTPUTTYPE {
+ OUTTYPE_SOURCE,
+ OUTTYPE_TITLE,
+};
+
+typedef unsigned long ARGB32;
+
+struct T_OUTPUT_TITLE {
+ wchar_t *Title;
+ wchar_t *Song;
+ wchar_t *Album;
+ wchar_t *Artist;
+ wchar_t *Genre;
+ wchar_t *Comment;
+ wchar_t *Year;
+ std::vector<std::wstring> NextList;
+ void *APIC[2];
+ int APICLength[2];
+ int APICType[2];
+
+ T_OUTPUT_TITLE() : Title(0), Song(0), Album(0), Artist(0), Genre(0), Comment(0), Year(0)
+ {
+ memset(APIC, 0, sizeof(void *) * 2);
+ memset(APICLength, 0, sizeof(int) * 2);
+ memset(APICType, 0, sizeof(int) * 2);
+ }
+
+
+ ~T_OUTPUT_TITLE()
+ {
+ if (Title)
+ {
+ free(Title);
+ Title = 0;
+ }
+
+ if (Song)
+ {
+ free(Song);
+ Song = 0;
+ }
+
+ if (Album)
+ {
+ free(Album);
+ Album = 0;
+ }
+
+ if (Artist)
+ {
+ free(Artist);
+ Artist = 0;
+ }
+
+ if (Genre)
+ {
+ free(Genre);
+ Genre = 0;
+ }
+
+ if (Comment)
+ {
+ free(Comment);
+ Comment = 0;
+ }
+
+ if (Year)
+ {
+ free(Year);
+ Year = 0;
+ }
+ }
+};
+
+struct T_OUTPUT_INFO {
+ unsigned int BytesSent; // how many bytes of content we've sent
+ clock_t ConnectionTime; // time a socket connection occurred
+ int Version; // server version
+ int Caps; // server capabilities
+ int Reconnect; // flag for the reconnection algorithm
+ int ReconnectTime; // value used in conjunction with the reconnection algorithm
+ int Succeeded; // had at least one successful connection (for reconnection alg.) -1 = password failure
+ int last_state; // using this as a means to allow for closing on errors but able to show a better message
+ int Switching; // if we're doing an automatic protocol version change (from v2 to v1)
+ char *ErrorMsg;
+ time_t ConnectedAt;
+ int meta_cached;
+ int art_cached[2];
+ unsigned short art_index[2];
+ unsigned short art_cached_span[2];
+ int art_cached_length[2];
+
+ // metadata information about the stream, etc
+ wchar_t *Title;
+ std::vector<std::wstring> NextList;
+ wchar_t *Song;
+ wchar_t *Album;
+ wchar_t *Artist;
+ wchar_t *Genre;
+ wchar_t *Comment;
+ wchar_t *Year;
+ void *APIC[2];
+ int APICLength[2];
+ int APICType[2];
+
+ T_OUTPUT_INFO() : BytesSent(0), ConnectionTime(0), Version(0),
+ Caps(0), Reconnect(0), ReconnectTime(0),
+ Succeeded(0), last_state(0), Switching(0),
+ ErrorMsg(0), ConnectedAt(0), meta_cached(0),
+ Title(0), Song(0), Album(0), Artist(0),
+ Genre(0), Comment(0), Year(0)
+ {
+ memset(art_cached, 0, sizeof(int) * 2);
+ memset(art_index, 0, sizeof(unsigned short) * 2);
+ memset(art_cached_span, 0, sizeof(unsigned short) * 2);
+ memset(art_cached_length, 0, sizeof(int) * 2);
+
+ memset(APIC, 0, sizeof(void *) * 2);
+ memset(APICLength, 0, sizeof(int) * 2);
+ memset(APICType, 0, sizeof(int) * 2);
+ }
+
+ ~T_OUTPUT_INFO()
+ {
+ if (Title)
+ {
+ free(Title);
+ Title = 0;
+ }
+
+ if (Song)
+ {
+ free(Song);
+ Song = 0;
+ }
+
+ if (Album)
+ {
+ free(Album);
+ Album = 0;
+ }
+
+ if (Artist)
+ {
+ free(Artist);
+ Artist = 0;
+ }
+
+ if (Genre)
+ {
+ free(Genre);
+ Genre = 0;
+ }
+
+ if (Comment)
+ {
+ free(Comment);
+ Comment = 0;
+ }
+
+ if (Year)
+ {
+ free(Year);
+ Year = 0;
+ }
+
+ if (Succeeded == -2 && ErrorMsg) {
+ free(ErrorMsg);
+ ErrorMsg = 0;
+ }
+ }
+};
+
+struct T_OUTPUT {
+ int Connection; // using this for the title update callback so the correct instance is updated
+ void (*TitleCallback)(const int Connection, const int Mode);
+ api_connection *Output;
+ enum OUTPUTTYPE Type;
+ int Bitrate; // this shouldn't be here, but it's the only way we can tell the shoutcast server the bitrate
+ char *ContentType; // neither should this
+ int SlowClose; // set to 1 to wait until all data is sent before closing the connection
+ T_OUTPUT_CONFIG *Config;
+ T_OUTPUT_INFO Info;
+
+ T_OUTPUT() : Connection(0), TitleCallback(0), Output(0), Type(OUTTYPE_SOURCE), Bitrate(0), ContentType(0), SlowClose(0), Config(0) {}
+};
+
+enum OUTPUTSTATE {
+ OUT_ERROR, // not a true state, but is returned when GetState() is called with an invalid connection handle
+ OUT_DISCONNECTED,
+ OUT_CONNECT,
+ OUT_REQUEST_CIPHER,
+ OUT_RECV_CIPHER,
+ OUT_SENDAUTH,
+ OUT_RECVAUTHRESPONSE,
+ OUT_SEND_MIME,
+ OUT_RECV_MIME,
+ OUT_SEND_BITRATE,
+ OUT_RECV_BITRATE,
+ OUT_SEND_BUFSIZE,
+ OUT_RECV_BUFSIZE,
+ OUT_SEND_MAX,
+ OUT_RECV_MAX,
+ OUT_SENDYP,
+ OUT_SEND_INITFLUSH,
+ OUT_RECV_INITFLUSH,
+ OUT_SEND_INITSTANDBY,
+ OUT_RECV_INITSTANDBY,
+ /*OUT_SEND_INTRO,
+ OUT_RECV_INTRO,
+ OUT_SEND_BACKUP,
+ OUT_RECV_BACKUP,*/
+ OUT_SENDCONTENT,
+ OUT_DISCONNECT,
+ OUT_RECONNECT,
+ OUT_TITLESENDUPDATE,
+ OUT_FAIL_CIPHER,
+ OUT_SEND_METADATA,
+ OUT_SEND_ARTWORK,
+};
+static void *mutex;
+
+class SHOUTCAST_OUTPUT {
+private:
+ C_ENCODER *Encoder;
+ int IOwnEncoder;
+ C_SERIAL_JOBMANAGER<T_OUTPUT> OutputManager;
+ T_OUTPUT_TITLE metadata;
+
+protected:
+ static int Output_Disconnected(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Connect(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Request_Cipher(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Receive_Cipher(int state, int last_state, T_OUTPUT *userData);
+ static int Output_SendAuth(int state, int last_state, T_OUTPUT *userData);
+ static int Output_RecvAuthResponse(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Send_Mime(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Recv_Mime(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Send_Bitrate(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Recv_Bitrate(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Send_Buf_Size(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Recv_Buf_Size(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Send_Max_Size(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Recv_Max_Size(int state, int last_state, T_OUTPUT *userData);
+ static int Output_DUMMY(int state, int last_state, T_OUTPUT *userData);
+ static int Output_SendYP(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Send_InitFlush(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Recv_InitFlush(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Send_InitStandby(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Recv_InitStandby(int state, int last_state, T_OUTPUT *userData);
+ /*static int Output_Send_Intro(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Recv_Intro(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Send_Backup(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Recv_Backup(int state, int last_state, T_OUTPUT *userData);*/
+ static int Output_SendContent(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Disconnect(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Reconnect(int state, int last_state, T_OUTPUT *userData);
+
+ static int Output_Title_SendUpdate(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Send_Metadata(int state, int last_state, T_OUTPUT *userData);
+ static int Output_Send_Artwork(int state, int last_state, T_OUTPUT *userData);
+
+ // uvox21
+ static void createUvoxFrame(int length, char *payload_in, int type, T_OUTPUT *userData);
+ static int createUvoxMetaFrame(int length, char *payload_in, int type,
+ T_OUTPUT *userData, unsigned short id, unsigned short span = 1);
+ static int parseUvoxFrame(char *payload_in, char *payload_out);
+ static int checkUvoxFrameForError(char *pload_out, int state, T_OUTPUT *userData);
+
+ void (*lame_init)(void);
+ void (*lame_init_params)(lame_global_flags *);
+ int (*lame_encode_buffer_interleaved)(lame_global_flags *, short int pcm[], int num_samples, char *mp3buffer, int mp3buffer_size);
+ int (*lame_encode_flush)(lame_global_flags *, char *mp3buffer, int size);
+
+ HINSTANCE libinst;
+
+public:
+ SHOUTCAST_OUTPUT();
+ void SetLame(void *init, void *params, void *encode, void *finish);
+ ~SHOUTCAST_OUTPUT();
+ int Run(int mode = 0, void *Input = NULL, int InputSize = 0, int SaveEncoder = -1);
+ int AddOutput(int Connection, T_OUTPUT_CONFIG *Config, void (*TitleCallback)(const int Connection, const int Mode)=0);
+ void UpdateOutput(int Connection);
+ void RemoveOutput(int Connection);
+ int ConnectOutput(int Connection);
+ int DisconnectOutput(int Connection, int withReconnect = 0, int reconnectTime = -1); // withReconnect of -1 will use the output config's setting
+ void SetEncoder(C_ENCODER *encoder, int takeOwnership = 0);
+
+ // we will attempt to cache the title information to save on duplication and
+ // also to make it easier for the title to be re-sent on server disconnect
+ void UpdateTitleCache(wchar_t *Title, std::vector<std::wstring> NextList, wchar_t *Song,
+ wchar_t *Album, wchar_t *Artist, wchar_t *Genre, wchar_t *Comment,
+ wchar_t* Year, int Connection, bool sendNext);
+ void UpdateTitle(wchar_t *Title, std::vector<std::wstring> NextList,
+ int Connection, bool sendNext, bool UseCache = true);
+
+ void UpdateArtwork(int Connection);
+ void UpdateAlbumArtCache(void* APIC, int APIClength, int APICType, int Connection);
+ int UpdateAlbumArt(int Connection);
+
+ enum OUTPUTSTATE GetState(int Connection);
+ T_OUTPUT_CONFIG *operator[](int Connection);
+ T_OUTPUT_CONFIG *GetOutput(int Connection);
+ C_ENCODER *GetEncoder();
+ T_OUTPUT_INFO *GetOutputInfo(int Connection);
+};
+static unsigned short mid = 1;
+
+#ifdef _DEBUG
+#define DEBUG_STATE OutputDebugString(__FUNCTION__); OutputDebugString("\r\n");
+#else
+#define DEBUG_STATE
+#endif
+
+#define STATE userData->Info.last_state = last_state
+#define LOCK if(WaitForSingleObject(mutex,INFINITE) == WAIT_OBJECT_0)
+#define UNLOCK ReleaseMutex(mutex);
+
+extern char sourceVersion[64];
+extern HWND hMainDLG;
+#endif // !__SHOUTCAST_OUTPUT_H__ \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/lame/include/lame.h b/Src/Plugins/DSP/dsp_sc/sc2srclib/lame/include/lame.h
new file mode 100644
index 00000000..3126cb95
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/lame/include/lame.h
@@ -0,0 +1,1323 @@
+/*
+ * Interface to MP3 LAME encoding engine
+ *
+ * Copyright (c) 1999 Mark Taylor
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* $Id: lame.h,v 1.4 2012/03/17 00:36:51 dromagod Exp $ */
+
+#ifndef LAME_LAME_H
+#define LAME_LAME_H
+
+/* for size_t typedef */
+#include <stddef.h>
+/* for va_list typedef */
+#include <stdarg.h>
+/* for FILE typedef, TODO: remove when removing lame_mp3_tags_fid */
+#include <stdio.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+typedef void (*lame_report_function)(const char *format, va_list ap);
+
+#if defined(WIN32) || defined(_WIN32)
+#undef CDECL
+#define CDECL __cdecl
+#else
+#define CDECL
+#endif
+
+#define DEPRECATED_OR_OBSOLETE_CODE_REMOVED 1
+
+typedef enum vbr_mode_e {
+ vbr_off=0,
+ vbr_mt, /* obsolete, same as vbr_mtrh */
+ vbr_rh,
+ vbr_abr,
+ vbr_mtrh,
+ vbr_max_indicator, /* Don't use this! It's used for sanity checks. */
+ vbr_default=vbr_mtrh /* change this to change the default VBR mode of LAME */
+} vbr_mode;
+
+
+/* MPEG modes */
+typedef enum MPEG_mode_e {
+ STEREO = 0,
+ JOINT_STEREO,
+ DUAL_CHANNEL, /* LAME doesn't supports this! */
+ MONO,
+ NOT_SET,
+ MAX_INDICATOR /* Don't use this! It's used for sanity checks. */
+} MPEG_mode;
+
+/* Padding types */
+typedef enum Padding_type_e {
+ PAD_NO = 0,
+ PAD_ALL,
+ PAD_ADJUST,
+ PAD_MAX_INDICATOR /* Don't use this! It's used for sanity checks. */
+} Padding_type;
+
+
+
+/*presets*/
+typedef enum preset_mode_e {
+ /*values from 8 to 320 should be reserved for abr bitrates*/
+ /*for abr I'd suggest to directly use the targeted bitrate as a value*/
+ ABR_8 = 8,
+ ABR_320 = 320,
+
+ V9 = 410, /*Vx to match Lame and VBR_xx to match FhG*/
+ VBR_10 = 410,
+ V8 = 420,
+ VBR_20 = 420,
+ V7 = 430,
+ VBR_30 = 430,
+ V6 = 440,
+ VBR_40 = 440,
+ V5 = 450,
+ VBR_50 = 450,
+ V4 = 460,
+ VBR_60 = 460,
+ V3 = 470,
+ VBR_70 = 470,
+ V2 = 480,
+ VBR_80 = 480,
+ V1 = 490,
+ VBR_90 = 490,
+ V0 = 500,
+ VBR_100 = 500,
+
+
+
+ /*still there for compatibility*/
+ R3MIX = 1000,
+ STANDARD = 1001,
+ EXTREME = 1002,
+ INSANE = 1003,
+ STANDARD_FAST = 1004,
+ EXTREME_FAST = 1005,
+ MEDIUM = 1006,
+ MEDIUM_FAST = 1007
+} preset_mode;
+
+
+/*asm optimizations*/
+typedef enum asm_optimizations_e {
+ MMX = 1,
+ AMD_3DNOW = 2,
+ SSE = 3
+} asm_optimizations;
+
+
+/* psychoacoustic model */
+typedef enum Psy_model_e {
+ PSY_GPSYCHO = 1,
+ PSY_NSPSYTUNE = 2
+} Psy_model;
+
+
+/* buffer considerations */
+typedef enum buffer_constraint_e {
+ MDB_DEFAULT=0,
+ MDB_STRICT_ISO=1,
+ MDB_MAXIMUM=2
+} buffer_constraint;
+
+
+struct lame_global_struct;
+typedef struct lame_global_struct lame_global_flags;
+typedef lame_global_flags *lame_t;
+
+
+
+
+/***********************************************************************
+ *
+ * The LAME API
+ * These functions should be called, in this order, for each
+ * MP3 file to be encoded. See the file "API" for more documentation
+ *
+ ***********************************************************************/
+
+
+/*
+ * REQUIRED:
+ * initialize the encoder. sets default for all encoder parameters,
+ * returns NULL if some malloc()'s failed
+ * otherwise returns pointer to structure needed for all future
+ * API calls.
+ */
+lame_global_flags * CDECL lame_init(void);
+#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED
+#else
+/* obsolete version */
+int CDECL lame_init_old(lame_global_flags *);
+#endif
+
+/*
+ * OPTIONAL:
+ * set as needed to override defaults
+ */
+
+/********************************************************************
+ * input stream description
+ ***********************************************************************/
+/* number of samples. default = 2^32-1 */
+int CDECL lame_set_num_samples(lame_global_flags *, unsigned long);
+unsigned long CDECL lame_get_num_samples(const lame_global_flags *);
+
+/* input sample rate in Hz. default = 44100hz */
+int CDECL lame_set_in_samplerate(lame_global_flags *, int);
+int CDECL lame_get_in_samplerate(const lame_global_flags *);
+
+/* number of channels in input stream. default=2 */
+int CDECL lame_set_num_channels(lame_global_flags *, int);
+int CDECL lame_get_num_channels(const lame_global_flags *);
+
+/*
+ scale the input by this amount before encoding. default=1
+ (not used by decoding routines)
+*/
+int CDECL lame_set_scale(lame_global_flags *, float);
+float CDECL lame_get_scale(const lame_global_flags *);
+
+/*
+ scale the channel 0 (left) input by this amount before encoding. default=1
+ (not used by decoding routines)
+*/
+int CDECL lame_set_scale_left(lame_global_flags *, float);
+float CDECL lame_get_scale_left(const lame_global_flags *);
+
+/*
+ scale the channel 1 (right) input by this amount before encoding. default=1
+ (not used by decoding routines)
+*/
+int CDECL lame_set_scale_right(lame_global_flags *, float);
+float CDECL lame_get_scale_right(const lame_global_flags *);
+
+/*
+ output sample rate in Hz. default = 0, which means LAME picks best value
+ based on the amount of compression. MPEG only allows:
+ MPEG1 32, 44.1, 48khz
+ MPEG2 16, 22.05, 24
+ MPEG2.5 8, 11.025, 12
+ (not used by decoding routines)
+*/
+int CDECL lame_set_out_samplerate(lame_global_flags *, int);
+int CDECL lame_get_out_samplerate(const lame_global_flags *);
+
+
+/********************************************************************
+ * general control parameters
+ ***********************************************************************/
+/* 1=cause LAME to collect data for an MP3 frame analyzer. default=0 */
+int CDECL lame_set_analysis(lame_global_flags *, int);
+int CDECL lame_get_analysis(const lame_global_flags *);
+
+/*
+ 1 = write a Xing VBR header frame.
+ default = 1
+ this variable must have been added by a Hungarian notation Windows programmer :-)
+*/
+int CDECL lame_set_bWriteVbrTag(lame_global_flags *, int);
+int CDECL lame_get_bWriteVbrTag(const lame_global_flags *);
+
+/* 1=decode only. use lame/mpglib to convert mp3/ogg to wav. default=0 */
+int CDECL lame_set_decode_only(lame_global_flags *, int);
+int CDECL lame_get_decode_only(const lame_global_flags *);
+
+#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED
+#else
+/* 1=encode a Vorbis .ogg file. default=0 */
+/* DEPRECATED */
+int CDECL lame_set_ogg(lame_global_flags *, int);
+int CDECL lame_get_ogg(const lame_global_flags *);
+#endif
+
+/*
+ internal algorithm selection. True quality is determined by the bitrate
+ but this variable will effect quality by selecting expensive or cheap algorithms.
+ quality=0..9. 0=best (very slow). 9=worst.
+ recommended: 2 near-best quality, not too slow
+ 5 good quality, fast
+ 7 ok quality, really fast
+*/
+int CDECL lame_set_quality(lame_global_flags *, int);
+int CDECL lame_get_quality(const lame_global_flags *);
+
+/*
+ mode = 0,1,2,3 = stereo, jstereo, dual channel (not supported), mono
+ default: lame picks based on compression ration and input channels
+*/
+int CDECL lame_set_mode(lame_global_flags *, MPEG_mode);
+MPEG_mode CDECL lame_get_mode(const lame_global_flags *);
+
+#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED
+#else
+/*
+ mode_automs. Use a M/S mode with a switching threshold based on
+ compression ratio
+ DEPRECATED
+*/
+int CDECL lame_set_mode_automs(lame_global_flags *, int);
+int CDECL lame_get_mode_automs(const lame_global_flags *);
+#endif
+
+/*
+ force_ms. Force M/S for all frames. For testing only.
+ default = 0 (disabled)
+*/
+int CDECL lame_set_force_ms(lame_global_flags *, int);
+int CDECL lame_get_force_ms(const lame_global_flags *);
+
+/* use free_format? default = 0 (disabled) */
+int CDECL lame_set_free_format(lame_global_flags *, int);
+int CDECL lame_get_free_format(const lame_global_flags *);
+
+/* perform ReplayGain analysis? default = 0 (disabled) */
+int CDECL lame_set_findReplayGain(lame_global_flags *, int);
+int CDECL lame_get_findReplayGain(const lame_global_flags *);
+
+/* decode on the fly. Search for the peak sample. If the ReplayGain
+ * analysis is enabled then perform the analysis on the decoded data
+ * stream. default = 0 (disabled)
+ * NOTE: if this option is set the build-in decoder should not be used */
+int CDECL lame_set_decode_on_the_fly(lame_global_flags *, int);
+int CDECL lame_get_decode_on_the_fly(const lame_global_flags *);
+
+#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED
+#else
+/* DEPRECATED: now does the same as lame_set_findReplayGain()
+ default = 0 (disabled) */
+int CDECL lame_set_ReplayGain_input(lame_global_flags *, int);
+int CDECL lame_get_ReplayGain_input(const lame_global_flags *);
+
+/* DEPRECATED: now does the same as
+ lame_set_decode_on_the_fly() && lame_set_findReplayGain()
+ default = 0 (disabled) */
+int CDECL lame_set_ReplayGain_decode(lame_global_flags *, int);
+int CDECL lame_get_ReplayGain_decode(const lame_global_flags *);
+
+/* DEPRECATED: now does the same as lame_set_decode_on_the_fly()
+ default = 0 (disabled) */
+int CDECL lame_set_findPeakSample(lame_global_flags *, int);
+int CDECL lame_get_findPeakSample(const lame_global_flags *);
+#endif
+
+/* counters for gapless encoding */
+int CDECL lame_set_nogap_total(lame_global_flags*, int);
+int CDECL lame_get_nogap_total(const lame_global_flags*);
+
+int CDECL lame_set_nogap_currentindex(lame_global_flags* , int);
+int CDECL lame_get_nogap_currentindex(const lame_global_flags*);
+
+
+/*
+ * OPTIONAL:
+ * Set printf like error/debug/message reporting functions.
+ * The second argument has to be a pointer to a function which looks like
+ * void my_debugf(const char *format, va_list ap)
+ * {
+ * (void) vfprintf(stdout, format, ap);
+ * }
+ * If you use NULL as the value of the pointer in the set function, the
+ * lame buildin function will be used (prints to stderr).
+ * To quiet any output you have to replace the body of the example function
+ * with just "return;" and use it in the set function.
+ */
+int CDECL lame_set_errorf(lame_global_flags *, lame_report_function);
+int CDECL lame_set_debugf(lame_global_flags *, lame_report_function);
+int CDECL lame_set_msgf (lame_global_flags *, lame_report_function);
+
+
+
+/* set one of brate compression ratio. default is compression ratio of 11. */
+int CDECL lame_set_brate(lame_global_flags *, int);
+int CDECL lame_get_brate(const lame_global_flags *);
+int CDECL lame_set_compression_ratio(lame_global_flags *, float);
+float CDECL lame_get_compression_ratio(const lame_global_flags *);
+
+
+int CDECL lame_set_preset( lame_global_flags* gfp, int );
+int CDECL lame_set_asm_optimizations( lame_global_flags* gfp, int, int );
+
+
+
+/********************************************************************
+ * frame params
+ ***********************************************************************/
+/* mark as copyright. default=0 */
+int CDECL lame_set_copyright(lame_global_flags *, int);
+int CDECL lame_get_copyright(const lame_global_flags *);
+
+/* mark as original. default=1 */
+int CDECL lame_set_original(lame_global_flags *, int);
+int CDECL lame_get_original(const lame_global_flags *);
+
+/* error_protection. Use 2 bytes from each frame for CRC checksum. default=0 */
+int CDECL lame_set_error_protection(lame_global_flags *, int);
+int CDECL lame_get_error_protection(const lame_global_flags *);
+
+#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED
+#else
+/* padding_type. 0=pad no frames 1=pad all frames 2=adjust padding(default) */
+int CDECL lame_set_padding_type(lame_global_flags *, Padding_type);
+Padding_type CDECL lame_get_padding_type(const lame_global_flags *);
+#endif
+
+/* MP3 'private extension' bit Meaningless. default=0 */
+int CDECL lame_set_extension(lame_global_flags *, int);
+int CDECL lame_get_extension(const lame_global_flags *);
+
+/* enforce strict ISO compliance. default=0 */
+int CDECL lame_set_strict_ISO(lame_global_flags *, int);
+int CDECL lame_get_strict_ISO(const lame_global_flags *);
+
+
+/********************************************************************
+ * quantization/noise shaping
+ ***********************************************************************/
+
+/* disable the bit reservoir. For testing only. default=0 */
+int CDECL lame_set_disable_reservoir(lame_global_flags *, int);
+int CDECL lame_get_disable_reservoir(const lame_global_flags *);
+
+/* select a different "best quantization" function. default=0 */
+int CDECL lame_set_quant_comp(lame_global_flags *, int);
+int CDECL lame_get_quant_comp(const lame_global_flags *);
+int CDECL lame_set_quant_comp_short(lame_global_flags *, int);
+int CDECL lame_get_quant_comp_short(const lame_global_flags *);
+
+int CDECL lame_set_experimentalX(lame_global_flags *, int); /* compatibility*/
+int CDECL lame_get_experimentalX(const lame_global_flags *);
+
+/* another experimental option. for testing only */
+int CDECL lame_set_experimentalY(lame_global_flags *, int);
+int CDECL lame_get_experimentalY(const lame_global_flags *);
+
+/* another experimental option. for testing only */
+int CDECL lame_set_experimentalZ(lame_global_flags *, int);
+int CDECL lame_get_experimentalZ(const lame_global_flags *);
+
+/* Naoki's psycho acoustic model. default=0 */
+int CDECL lame_set_exp_nspsytune(lame_global_flags *, int);
+int CDECL lame_get_exp_nspsytune(const lame_global_flags *);
+
+void CDECL lame_set_msfix(lame_global_flags *, double);
+float CDECL lame_get_msfix(const lame_global_flags *);
+
+
+/********************************************************************
+ * VBR control
+ ***********************************************************************/
+/* Types of VBR. default = vbr_off = CBR */
+int CDECL lame_set_VBR(lame_global_flags *, vbr_mode);
+vbr_mode CDECL lame_get_VBR(const lame_global_flags *);
+
+/* VBR quality level. 0=highest 9=lowest */
+int CDECL lame_set_VBR_q(lame_global_flags *, int);
+int CDECL lame_get_VBR_q(const lame_global_flags *);
+
+/* VBR quality level. 0=highest 9=lowest, Range [0,...,10[ */
+int CDECL lame_set_VBR_quality(lame_global_flags *, float);
+float CDECL lame_get_VBR_quality(const lame_global_flags *);
+
+/* Ignored except for VBR=vbr_abr (ABR mode) */
+int CDECL lame_set_VBR_mean_bitrate_kbps(lame_global_flags *, int);
+int CDECL lame_get_VBR_mean_bitrate_kbps(const lame_global_flags *);
+
+int CDECL lame_set_VBR_min_bitrate_kbps(lame_global_flags *, int);
+int CDECL lame_get_VBR_min_bitrate_kbps(const lame_global_flags *);
+
+int CDECL lame_set_VBR_max_bitrate_kbps(lame_global_flags *, int);
+int CDECL lame_get_VBR_max_bitrate_kbps(const lame_global_flags *);
+
+/*
+ 1=strictly enforce VBR_min_bitrate. Normally it will be violated for
+ analog silence
+*/
+int CDECL lame_set_VBR_hard_min(lame_global_flags *, int);
+int CDECL lame_get_VBR_hard_min(const lame_global_flags *);
+
+/* for preset */
+#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED
+#else
+int CDECL lame_set_preset_expopts(lame_global_flags *, int);
+#endif
+
+/********************************************************************
+ * Filtering control
+ ***********************************************************************/
+/* freq in Hz to apply lowpass. Default = 0 = lame chooses. -1 = disabled */
+int CDECL lame_set_lowpassfreq(lame_global_flags *, int);
+int CDECL lame_get_lowpassfreq(const lame_global_flags *);
+/* width of transition band, in Hz. Default = one polyphase filter band */
+int CDECL lame_set_lowpasswidth(lame_global_flags *, int);
+int CDECL lame_get_lowpasswidth(const lame_global_flags *);
+
+/* freq in Hz to apply highpass. Default = 0 = lame chooses. -1 = disabled */
+int CDECL lame_set_highpassfreq(lame_global_flags *, int);
+int CDECL lame_get_highpassfreq(const lame_global_flags *);
+/* width of transition band, in Hz. Default = one polyphase filter band */
+int CDECL lame_set_highpasswidth(lame_global_flags *, int);
+int CDECL lame_get_highpasswidth(const lame_global_flags *);
+
+
+/********************************************************************
+ * psycho acoustics and other arguments which you should not change
+ * unless you know what you are doing
+ ***********************************************************************/
+
+/* only use ATH for masking */
+int CDECL lame_set_ATHonly(lame_global_flags *, int);
+int CDECL lame_get_ATHonly(const lame_global_flags *);
+
+/* only use ATH for short blocks */
+int CDECL lame_set_ATHshort(lame_global_flags *, int);
+int CDECL lame_get_ATHshort(const lame_global_flags *);
+
+/* disable ATH */
+int CDECL lame_set_noATH(lame_global_flags *, int);
+int CDECL lame_get_noATH(const lame_global_flags *);
+
+/* select ATH formula */
+int CDECL lame_set_ATHtype(lame_global_flags *, int);
+int CDECL lame_get_ATHtype(const lame_global_flags *);
+
+/* lower ATH by this many db */
+int CDECL lame_set_ATHlower(lame_global_flags *, float);
+float CDECL lame_get_ATHlower(const lame_global_flags *);
+
+/* select ATH adaptive adjustment type */
+int CDECL lame_set_athaa_type( lame_global_flags *, int);
+int CDECL lame_get_athaa_type( const lame_global_flags *);
+
+#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED
+#else
+/* select the loudness approximation used by the ATH adaptive auto-leveling */
+int CDECL lame_set_athaa_loudapprox( lame_global_flags *, int);
+int CDECL lame_get_athaa_loudapprox( const lame_global_flags *);
+#endif
+
+/* adjust (in dB) the point below which adaptive ATH level adjustment occurs */
+int CDECL lame_set_athaa_sensitivity( lame_global_flags *, float);
+float CDECL lame_get_athaa_sensitivity( const lame_global_flags* );
+
+#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED
+#else
+/* OBSOLETE: predictability limit (ISO tonality formula) */
+int CDECL lame_set_cwlimit(lame_global_flags *, int);
+int CDECL lame_get_cwlimit(const lame_global_flags *);
+#endif
+
+/*
+ allow blocktypes to differ between channels?
+ default: 0 for jstereo, 1 for stereo
+*/
+int CDECL lame_set_allow_diff_short(lame_global_flags *, int);
+int CDECL lame_get_allow_diff_short(const lame_global_flags *);
+
+/* use temporal masking effect (default = 1) */
+int CDECL lame_set_useTemporal(lame_global_flags *, int);
+int CDECL lame_get_useTemporal(const lame_global_flags *);
+
+/* use temporal masking effect (default = 1) */
+int CDECL lame_set_interChRatio(lame_global_flags *, float);
+float CDECL lame_get_interChRatio(const lame_global_flags *);
+
+/* disable short blocks */
+int CDECL lame_set_no_short_blocks(lame_global_flags *, int);
+int CDECL lame_get_no_short_blocks(const lame_global_flags *);
+
+/* force short blocks */
+int CDECL lame_set_force_short_blocks(lame_global_flags *, int);
+int CDECL lame_get_force_short_blocks(const lame_global_flags *);
+
+/* Input PCM is emphased PCM (for instance from one of the rarely
+ emphased CDs), it is STRONGLY not recommended to use this, because
+ psycho does not take it into account, and last but not least many decoders
+ ignore these bits */
+int CDECL lame_set_emphasis(lame_global_flags *, int);
+int CDECL lame_get_emphasis(const lame_global_flags *);
+
+
+
+/************************************************************************/
+/* internal variables, cannot be set... */
+/* provided because they may be of use to calling application */
+/************************************************************************/
+/* version 0=MPEG-2 1=MPEG-1 (2=MPEG-2.5) */
+int CDECL lame_get_version(const lame_global_flags *);
+
+/* encoder delay */
+int CDECL lame_get_encoder_delay(const lame_global_flags *);
+
+/*
+ padding appended to the input to make sure decoder can fully decode
+ all input. Note that this value can only be calculated during the
+ call to lame_encoder_flush(). Before lame_encoder_flush() has
+ been called, the value of encoder_padding = 0.
+*/
+int CDECL lame_get_encoder_padding(const lame_global_flags *);
+
+/* size of MPEG frame */
+int CDECL lame_get_framesize(const lame_global_flags *);
+
+/* number of PCM samples buffered, but not yet encoded to mp3 data. */
+int CDECL lame_get_mf_samples_to_encode( const lame_global_flags* gfp );
+
+/*
+ size (bytes) of mp3 data buffered, but not yet encoded.
+ this is the number of bytes which would be output by a call to
+ lame_encode_flush_nogap. NOTE: lame_encode_flush() will return
+ more bytes than this because it will encode the reamining buffered
+ PCM samples before flushing the mp3 buffers.
+*/
+int CDECL lame_get_size_mp3buffer( const lame_global_flags* gfp );
+
+/* number of frames encoded so far */
+int CDECL lame_get_frameNum(const lame_global_flags *);
+
+/*
+ lame's estimate of the total number of frames to be encoded
+ only valid if calling program set num_samples
+*/
+int CDECL lame_get_totalframes(const lame_global_flags *);
+
+/* RadioGain value. Multiplied by 10 and rounded to the nearest. */
+int CDECL lame_get_RadioGain(const lame_global_flags *);
+
+/* AudiophileGain value. Multipled by 10 and rounded to the nearest. */
+int CDECL lame_get_AudiophileGain(const lame_global_flags *);
+
+/* the peak sample */
+float CDECL lame_get_PeakSample(const lame_global_flags *);
+
+/* Gain change required for preventing clipping. The value is correct only if
+ peak sample searching was enabled. If negative then the waveform
+ already does not clip. The value is multiplied by 10 and rounded up. */
+int CDECL lame_get_noclipGainChange(const lame_global_flags *);
+
+/* user-specified scale factor required for preventing clipping. Value is
+ correct only if peak sample searching was enabled and no user-specified
+ scaling was performed. If negative then either the waveform already does
+ not clip or the value cannot be determined */
+float CDECL lame_get_noclipScale(const lame_global_flags *);
+
+
+
+
+
+
+
+/*
+ * REQUIRED:
+ * sets more internal configuration based on data provided above.
+ * returns -1 if something failed.
+ */
+int CDECL lame_init_params(lame_global_flags *);
+
+
+/*
+ * OPTIONAL:
+ * get the version number, in a string. of the form:
+ * "3.63 (beta)" or just "3.63".
+ */
+const char* CDECL get_lame_version ( void );
+const char* CDECL get_lame_short_version ( void );
+const char* CDECL get_lame_very_short_version ( void );
+const char* CDECL get_psy_version ( void );
+const char* CDECL get_lame_url ( void );
+const char* CDECL get_lame_os_bitness ( void );
+
+/*
+ * OPTIONAL:
+ * get the version numbers in numerical form.
+ */
+typedef struct {
+ /* generic LAME version */
+ int major;
+ int minor;
+ int alpha; /* 0 if not an alpha version */
+ int beta; /* 0 if not a beta version */
+
+ /* version of the psy model */
+ int psy_major;
+ int psy_minor;
+ int psy_alpha; /* 0 if not an alpha version */
+ int psy_beta; /* 0 if not a beta version */
+
+ /* compile time features */
+ const char *features; /* Don't make assumptions about the contents! */
+} lame_version_t;
+void CDECL get_lame_version_numerical(lame_version_t *);
+
+
+/*
+ * OPTIONAL:
+ * print internal lame configuration to message handler
+ */
+void CDECL lame_print_config(const lame_global_flags* gfp);
+
+void CDECL lame_print_internals( const lame_global_flags *gfp);
+
+
+/*
+ * input pcm data, output (maybe) mp3 frames.
+ * This routine handles all buffering, resampling and filtering for you.
+ *
+ * return code number of bytes output in mp3buf. Can be 0
+ * -1: mp3buf was too small
+ * -2: malloc() problem
+ * -3: lame_init_params() not called
+ * -4: psycho acoustic problems
+ *
+ * The required mp3buf_size can be computed from num_samples,
+ * samplerate and encoding rate, but here is a worst case estimate:
+ *
+ * mp3buf_size in bytes = 1.25*num_samples + 7200
+ *
+ * I think a tighter bound could be: (mt, March 2000)
+ * MPEG1:
+ * num_samples*(bitrate/8)/samplerate + 4*1152*(bitrate/8)/samplerate + 512
+ * MPEG2:
+ * num_samples*(bitrate/8)/samplerate + 4*576*(bitrate/8)/samplerate + 256
+ *
+ * but test first if you use that!
+ *
+ * set mp3buf_size = 0 and LAME will not check if mp3buf_size is
+ * large enough.
+ *
+ * NOTE:
+ * if gfp->num_channels=2, but gfp->mode = 3 (mono), the L & R channels
+ * will be averaged into the L channel before encoding only the L channel
+ * This will overwrite the data in buffer_l[] and buffer_r[].
+ *
+*/
+int CDECL lame_encode_buffer (
+ lame_global_flags* gfp, /* global context handle */
+ const short int buffer_l [], /* PCM data for left channel */
+ const short int buffer_r [], /* PCM data for right channel */
+ const int nsamples, /* number of samples per channel */
+ unsigned char* mp3buf, /* pointer to encoded MP3 stream */
+ const int mp3buf_size ); /* number of valid octets in this
+ stream */
+
+/*
+ * as above, but input has L & R channel data interleaved.
+ * NOTE:
+ * num_samples = number of samples in the L (or R)
+ * channel, not the total number of samples in pcm[]
+ */
+int CDECL lame_encode_buffer_interleaved(
+ lame_global_flags* gfp, /* global context handlei */
+ short int pcm[], /* PCM data for left and right
+ channel, interleaved */
+ int num_samples, /* number of samples per channel,
+ _not_ number of samples in
+ pcm[] */
+ unsigned char* mp3buf, /* pointer to encoded MP3 stream */
+ int mp3buf_size ); /* number of valid octets in this
+ stream */
+
+
+/* as lame_encode_buffer, but for 'float's.
+ * !! NOTE: !! data must still be scaled to be in the same range as
+ * short int, +/- 32768
+ */
+int CDECL lame_encode_buffer_float(
+ lame_global_flags* gfp, /* global context handle */
+ const float pcm_l [], /* PCM data for left channel */
+ const float pcm_r [], /* PCM data for right channel */
+ const int nsamples, /* number of samples per channel */
+ unsigned char* mp3buf, /* pointer to encoded MP3 stream */
+ const int mp3buf_size ); /* number of valid octets in this
+ stream */
+
+/* as lame_encode_buffer, but for 'float's.
+ * !! NOTE: !! data must be scaled to +/- 1 full scale
+ */
+int CDECL lame_encode_buffer_ieee_float(
+ lame_t gfp,
+ const float pcm_l [], /* PCM data for left channel */
+ const float pcm_r [], /* PCM data for right channel */
+ const int nsamples,
+ unsigned char * mp3buf,
+ const int mp3buf_size);
+int CDECL lame_encode_buffer_interleaved_ieee_float(
+ lame_t gfp,
+ const float pcm[], /* PCM data for left and right
+ channel, interleaved */
+ const int nsamples,
+ unsigned char * mp3buf,
+ const int mp3buf_size);
+
+/* as lame_encode_buffer, but for 'double's.
+ * !! NOTE: !! data must be scaled to +/- 1 full scale
+ */
+int CDECL lame_encode_buffer_ieee_double(
+ lame_t gfp,
+ const double pcm_l [], /* PCM data for left channel */
+ const double pcm_r [], /* PCM data for right channel */
+ const int nsamples,
+ unsigned char * mp3buf,
+ const int mp3buf_size);
+int CDECL lame_encode_buffer_interleaved_ieee_double(
+ lame_t gfp,
+ const double pcm[], /* PCM data for left and right
+ channel, interleaved */
+ const int nsamples,
+ unsigned char * mp3buf,
+ const int mp3buf_size);
+
+/* as lame_encode_buffer, but for long's
+ * !! NOTE: !! data must still be scaled to be in the same range as
+ * short int, +/- 32768
+ *
+ * This scaling was a mistake (doesn't allow one to exploit full
+ * precision of type 'long'. Use lame_encode_buffer_long2() instead.
+ *
+ */
+int CDECL lame_encode_buffer_long(
+ lame_global_flags* gfp, /* global context handle */
+ const long buffer_l [], /* PCM data for left channel */
+ const long buffer_r [], /* PCM data for right channel */
+ const int nsamples, /* number of samples per channel */
+ unsigned char* mp3buf, /* pointer to encoded MP3 stream */
+ const int mp3buf_size ); /* number of valid octets in this
+ stream */
+
+/* Same as lame_encode_buffer_long(), but with correct scaling.
+ * !! NOTE: !! data must still be scaled to be in the same range as
+ * type 'long'. Data should be in the range: +/- 2^(8*size(long)-1)
+ *
+ */
+int CDECL lame_encode_buffer_long2(
+ lame_global_flags* gfp, /* global context handle */
+ const long buffer_l [], /* PCM data for left channel */
+ const long buffer_r [], /* PCM data for right channel */
+ const int nsamples, /* number of samples per channel */
+ unsigned char* mp3buf, /* pointer to encoded MP3 stream */
+ const int mp3buf_size ); /* number of valid octets in this
+ stream */
+
+/* as lame_encode_buffer, but for int's
+ * !! NOTE: !! input should be scaled to the maximum range of 'int'
+ * If int is 4 bytes, then the values should range from
+ * +/- 2147483648.
+ *
+ * This routine does not (and cannot, without loosing precision) use
+ * the same scaling as the rest of the lame_encode_buffer() routines.
+ *
+ */
+int CDECL lame_encode_buffer_int(
+ lame_global_flags* gfp, /* global context handle */
+ const int buffer_l [], /* PCM data for left channel */
+ const int buffer_r [], /* PCM data for right channel */
+ const int nsamples, /* number of samples per channel */
+ unsigned char* mp3buf, /* pointer to encoded MP3 stream */
+ const int mp3buf_size ); /* number of valid octets in this
+ stream */
+
+
+
+
+
+/*
+ * REQUIRED:
+ * lame_encode_flush will flush the intenal PCM buffers, padding with
+ * 0's to make sure the final frame is complete, and then flush
+ * the internal MP3 buffers, and thus may return a
+ * final few mp3 frames. 'mp3buf' should be at least 7200 bytes long
+ * to hold all possible emitted data.
+ *
+ * will also write id3v1 tags (if any) into the bitstream
+ *
+ * return code = number of bytes output to mp3buf. Can be 0
+ */
+int CDECL lame_encode_flush(
+ lame_global_flags * gfp, /* global context handle */
+ unsigned char* mp3buf, /* pointer to encoded MP3 stream */
+ int size); /* number of valid octets in this stream */
+
+/*
+ * OPTIONAL:
+ * lame_encode_flush_nogap will flush the internal mp3 buffers and pad
+ * the last frame with ancillary data so it is a complete mp3 frame.
+ *
+ * 'mp3buf' should be at least 7200 bytes long
+ * to hold all possible emitted data.
+ *
+ * After a call to this routine, the outputed mp3 data is complete, but
+ * you may continue to encode new PCM samples and write future mp3 data
+ * to a different file. The two mp3 files will play back with no gaps
+ * if they are concatenated together.
+ *
+ * This routine will NOT write id3v1 tags into the bitstream.
+ *
+ * return code = number of bytes output to mp3buf. Can be 0
+ */
+int CDECL lame_encode_flush_nogap(
+ lame_global_flags * gfp, /* global context handle */
+ unsigned char* mp3buf, /* pointer to encoded MP3 stream */
+ int size); /* number of valid octets in this stream */
+
+/*
+ * OPTIONAL:
+ * Normally, this is called by lame_init_params(). It writes id3v2 and
+ * Xing headers into the front of the bitstream, and sets frame counters
+ * and bitrate histogram data to 0. You can also call this after
+ * lame_encode_flush_nogap().
+ */
+int CDECL lame_init_bitstream(
+ lame_global_flags * gfp); /* global context handle */
+
+
+
+/*
+ * OPTIONAL: some simple statistics
+ * a bitrate histogram to visualize the distribution of used frame sizes
+ * a stereo mode histogram to visualize the distribution of used stereo
+ * modes, useful in joint-stereo mode only
+ * 0: LR left-right encoded
+ * 1: LR-I left-right and intensity encoded (currently not supported)
+ * 2: MS mid-side encoded
+ * 3: MS-I mid-side and intensity encoded (currently not supported)
+ *
+ * attention: don't call them after lame_encode_finish
+ * suggested: lame_encode_flush -> lame_*_hist -> lame_close
+ */
+
+void CDECL lame_bitrate_hist(
+ const lame_global_flags * gfp,
+ int bitrate_count[14] );
+void CDECL lame_bitrate_kbps(
+ const lame_global_flags * gfp,
+ int bitrate_kbps [14] );
+void CDECL lame_stereo_mode_hist(
+ const lame_global_flags * gfp,
+ int stereo_mode_count[4] );
+
+void CDECL lame_bitrate_stereo_mode_hist (
+ const lame_global_flags * gfp,
+ int bitrate_stmode_count[14][4] );
+
+void CDECL lame_block_type_hist (
+ const lame_global_flags * gfp,
+ int btype_count[6] );
+
+void CDECL lame_bitrate_block_type_hist (
+ const lame_global_flags * gfp,
+ int bitrate_btype_count[14][6] );
+
+#if (DEPRECATED_OR_OBSOLETE_CODE_REMOVED && 0)
+#else
+/*
+ * OPTIONAL:
+ * lame_mp3_tags_fid will rewrite a Xing VBR tag to the mp3 file with file
+ * pointer fid. These calls perform forward and backwards seeks, so make
+ * sure fid is a real file. Make sure lame_encode_flush has been called,
+ * and all mp3 data has been written to the file before calling this
+ * function.
+ * NOTE:
+ * if VBR tags are turned off by the user, or turned off by LAME because
+ * the output is not a regular file, this call does nothing
+ * NOTE:
+ * LAME wants to read from the file to skip an optional ID3v2 tag, so
+ * make sure you opened the file for writing and reading.
+ * NOTE:
+ * You can call lame_get_lametag_frame instead, if you want to insert
+ * the lametag yourself.
+*/
+void CDECL lame_mp3_tags_fid(lame_global_flags *, FILE* fid);
+#endif
+
+/*
+ * OPTIONAL:
+ * lame_get_lametag_frame copies the final LAME-tag into 'buffer'.
+ * The function returns the number of bytes copied into buffer, or
+ * the required buffer size, if the provided buffer is too small.
+ * Function failed, if the return value is larger than 'size'!
+ * Make sure lame_encode flush has been called before calling this function.
+ * NOTE:
+ * if VBR tags are turned off by the user, or turned off by LAME,
+ * this call does nothing and returns 0.
+ * NOTE:
+ * LAME inserted an empty frame in the beginning of mp3 audio data,
+ * which you have to replace by the final LAME-tag frame after encoding.
+ * In case there is no ID3v2 tag, usually this frame will be the very first
+ * data in your mp3 file. If you put some other leading data into your
+ * file, you'll have to do some bookkeeping about where to write this buffer.
+ */
+size_t CDECL lame_get_lametag_frame(
+ const lame_global_flags *, unsigned char* buffer, size_t size);
+
+/*
+ * REQUIRED:
+ * final call to free all remaining buffers
+ */
+int CDECL lame_close (lame_global_flags *);
+
+#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED
+#else
+/*
+ * OBSOLETE:
+ * lame_encode_finish combines lame_encode_flush() and lame_close() in
+ * one call. However, once this call is made, the statistics routines
+ * will no longer work because the data will have been cleared, and
+ * lame_mp3_tags_fid() cannot be called to add data to the VBR header
+ */
+int CDECL lame_encode_finish(
+ lame_global_flags* gfp,
+ unsigned char* mp3buf,
+ int size );
+#endif
+
+
+
+
+
+
+/*********************************************************************
+ *
+ * decoding
+ *
+ * a simple interface to mpglib, part of mpg123, is also included if
+ * libmp3lame is compiled with HAVE_MPGLIB
+ *
+ *********************************************************************/
+
+struct hip_global_struct;
+typedef struct hip_global_struct hip_global_flags;
+typedef hip_global_flags *hip_t;
+
+
+typedef struct {
+ int header_parsed; /* 1 if header was parsed and following data was
+ computed */
+ int stereo; /* number of channels */
+ int samplerate; /* sample rate */
+ int bitrate; /* bitrate */
+ int mode; /* mp3 frame type */
+ int mode_ext; /* mp3 frame type */
+ int framesize; /* number of samples per mp3 frame */
+
+ /* this data is only computed if mpglib detects a Xing VBR header */
+ unsigned long nsamp; /* number of samples in mp3 file. */
+ int totalframes; /* total number of frames in mp3 file */
+
+ /* this data is not currently computed by the mpglib routines */
+ int framenum; /* frames decoded counter */
+} mp3data_struct;
+
+/* required call to initialize decoder */
+hip_t CDECL hip_decode_init(void);
+
+/* cleanup call to exit decoder */
+int CDECL hip_decode_exit(hip_t gfp);
+
+/* HIP reporting functions */
+void CDECL hip_set_errorf(hip_t gfp, lame_report_function f);
+void CDECL hip_set_debugf(hip_t gfp, lame_report_function f);
+void CDECL hip_set_msgf (hip_t gfp, lame_report_function f);
+
+/*********************************************************************
+ * input 1 mp3 frame, output (maybe) pcm data.
+ *
+ * nout = hip_decode(hip, mp3buf,len,pcm_l,pcm_r);
+ *
+ * input:
+ * len : number of bytes of mp3 data in mp3buf
+ * mp3buf[len] : mp3 data to be decoded
+ *
+ * output:
+ * nout: -1 : decoding error
+ * 0 : need more data before we can complete the decode
+ * >0 : returned 'nout' samples worth of data in pcm_l,pcm_r
+ * pcm_l[nout] : left channel data
+ * pcm_r[nout] : right channel data
+ *
+ *********************************************************************/
+int CDECL hip_decode( hip_t gfp
+ , unsigned char * mp3buf
+ , size_t len
+ , short pcm_l[]
+ , short pcm_r[]
+ );
+
+/* same as hip_decode, and also returns mp3 header data */
+int CDECL hip_decode_headers( hip_t gfp
+ , unsigned char* mp3buf
+ , size_t len
+ , short pcm_l[]
+ , short pcm_r[]
+ , mp3data_struct* mp3data
+ );
+
+/* same as hip_decode, but returns at most one frame */
+int CDECL hip_decode1( hip_t gfp
+ , unsigned char* mp3buf
+ , size_t len
+ , short pcm_l[]
+ , short pcm_r[]
+ );
+
+/* same as hip_decode1, but returns at most one frame and mp3 header data */
+int CDECL hip_decode1_headers( hip_t gfp
+ , unsigned char* mp3buf
+ , size_t len
+ , short pcm_l[]
+ , short pcm_r[]
+ , mp3data_struct* mp3data
+ );
+
+/* same as hip_decode1_headers, but also returns enc_delay and enc_padding
+ from VBR Info tag, (-1 if no info tag was found) */
+int CDECL hip_decode1_headersB( hip_t gfp
+ , unsigned char* mp3buf
+ , size_t len
+ , short pcm_l[]
+ , short pcm_r[]
+ , mp3data_struct* mp3data
+ , int *enc_delay
+ , int *enc_padding
+ );
+
+
+
+/* OBSOLETE:
+ * lame_decode... functions are there to keep old code working
+ * but it is strongly recommended to replace calls by hip_decode...
+ * function calls, see above.
+ */
+#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED
+#else
+int CDECL lame_decode_init(void);
+int CDECL lame_decode(
+ unsigned char * mp3buf,
+ int len,
+ short pcm_l[],
+ short pcm_r[] );
+int CDECL lame_decode_headers(
+ unsigned char* mp3buf,
+ int len,
+ short pcm_l[],
+ short pcm_r[],
+ mp3data_struct* mp3data );
+int CDECL lame_decode1(
+ unsigned char* mp3buf,
+ int len,
+ short pcm_l[],
+ short pcm_r[] );
+int CDECL lame_decode1_headers(
+ unsigned char* mp3buf,
+ int len,
+ short pcm_l[],
+ short pcm_r[],
+ mp3data_struct* mp3data );
+int CDECL lame_decode1_headersB(
+ unsigned char* mp3buf,
+ int len,
+ short pcm_l[],
+ short pcm_r[],
+ mp3data_struct* mp3data,
+ int *enc_delay,
+ int *enc_padding );
+int CDECL lame_decode_exit(void);
+
+#endif /* obsolete lame_decode API calls */
+
+
+/*********************************************************************
+ *
+ * id3tag stuff
+ *
+ *********************************************************************/
+
+/*
+ * id3tag.h -- Interface to write ID3 version 1 and 2 tags.
+ *
+ * Copyright (C) 2000 Don Melton.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* utility to obtain alphabetically sorted list of genre names with numbers */
+void CDECL id3tag_genre_list(
+ void (*handler)(int, const char *, void *),
+ void* cookie);
+
+void CDECL id3tag_init (lame_t gfp);
+
+/* force addition of version 2 tag */
+void CDECL id3tag_add_v2 (lame_t gfp);
+
+/* add only a version 1 tag */
+void CDECL id3tag_v1_only (lame_t gfp);
+
+/* add only a version 2 tag */
+void CDECL id3tag_v2_only (lame_t gfp);
+
+/* pad version 1 tag with spaces instead of nulls */
+void CDECL id3tag_space_v1 (lame_t gfp);
+
+/* pad version 2 tag with extra 128 bytes */
+void CDECL id3tag_pad_v2 (lame_t gfp);
+
+/* pad version 2 tag with extra n bytes */
+void CDECL id3tag_set_pad (lame_t gfp, size_t n);
+
+void CDECL id3tag_set_title(lame_t gfp, const char* title);
+void CDECL id3tag_set_artist(lame_t gfp, const char* artist);
+void CDECL id3tag_set_album(lame_t gfp, const char* album);
+void CDECL id3tag_set_year(lame_t gfp, const char* year);
+void CDECL id3tag_set_comment(lame_t gfp, const char* comment);
+
+/* return -1 result if track number is out of ID3v1 range
+ and ignored for ID3v1 */
+int CDECL id3tag_set_track(lame_t gfp, const char* track);
+
+/* return non-zero result if genre name or number is invalid
+ result 0: OK
+ result -1: genre number out of range
+ result -2: no valid ID3v1 genre name, mapped to ID3v1 'Other'
+ but taken as-is for ID3v2 genre tag */
+int CDECL id3tag_set_genre(lame_t gfp, const char* genre);
+
+/* return non-zero result if field name is invalid */
+int CDECL id3tag_set_fieldvalue(lame_t gfp, const char* fieldvalue);
+
+/* return non-zero result if image type is invalid */
+int CDECL id3tag_set_albumart(lame_t gfp, const char* image, size_t size);
+
+/* lame_get_id3v1_tag copies ID3v1 tag into buffer.
+ * Function returns number of bytes copied into buffer, or number
+ * of bytes rquired if buffer 'size' is too small.
+ * Function fails, if returned value is larger than 'size'.
+ * NOTE:
+ * This functions does nothing, if user/LAME disabled ID3v1 tag.
+ */
+size_t CDECL lame_get_id3v1_tag(lame_t gfp, unsigned char* buffer, size_t size);
+
+/* lame_get_id3v2_tag copies ID3v2 tag into buffer.
+ * Function returns number of bytes copied into buffer, or number
+ * of bytes rquired if buffer 'size' is too small.
+ * Function fails, if returned value is larger than 'size'.
+ * NOTE:
+ * This functions does nothing, if user/LAME disabled ID3v2 tag.
+ */
+size_t CDECL lame_get_id3v2_tag(lame_t gfp, unsigned char* buffer, size_t size);
+
+/* normaly lame_init_param writes ID3v2 tags into the audio stream
+ * Call lame_set_write_id3tag_automatic(gfp, 0) before lame_init_param
+ * to turn off this behaviour and get ID3v2 tag with above function
+ * write it yourself into your file.
+ */
+void CDECL lame_set_write_id3tag_automatic(lame_global_flags * gfp, int);
+int CDECL lame_get_write_id3tag_automatic(lame_global_flags const* gfp);
+
+/* experimental */
+int CDECL id3tag_set_textinfo_latin1(lame_t gfp, char const *id, char const *text);
+
+/* experimental */
+int CDECL id3tag_set_comment_latin1(lame_t gfp, char const *lang, char const *desc, char const *text);
+
+#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED
+#else
+/* experimental */
+int CDECL id3tag_set_textinfo_ucs2(lame_t gfp, char const *id, unsigned short const *text);
+
+/* experimental */
+int CDECL id3tag_set_comment_ucs2(lame_t gfp, char const *lang,
+ unsigned short const *desc, unsigned short const *text);
+
+/* experimental */
+int CDECL id3tag_set_fieldvalue_ucs2(lame_t gfp, const unsigned short *fieldvalue);
+#endif
+
+/* experimental */
+int CDECL id3tag_set_fieldvalue_utf16(lame_t gfp, const unsigned short *fieldvalue);
+
+/* experimental */
+int CDECL id3tag_set_textinfo_utf16(lame_t gfp, char const *id, unsigned short const *text);
+
+/* experimental */
+int CDECL id3tag_set_comment_utf16(lame_t gfp, char const *lang, unsigned short const *desc, unsigned short const *text);
+
+
+/***********************************************************************
+*
+* list of valid bitrates [kbps] & sample frequencies [Hz].
+* first index: 0: MPEG-2 values (sample frequencies 16...24 kHz)
+* 1: MPEG-1 values (sample frequencies 32...48 kHz)
+* 2: MPEG-2.5 values (sample frequencies 8...12 kHz)
+***********************************************************************/
+
+extern const int bitrate_table [3][16];
+extern const int samplerate_table [3][ 4];
+
+/* access functions for use in DLL, global vars are not exported */
+int CDECL lame_get_bitrate(int mpeg_version, int table_index);
+int CDECL lame_get_samplerate(int mpeg_version, int table_index);
+
+
+/* maximum size of albumart image (128KB), which affects LAME_MAXMP3BUFFER
+ as well since lame_encode_buffer() also returns ID3v2 tag data */
+#define LAME_MAXALBUMART (128 * 1024)
+
+/* maximum size of mp3buffer needed if you encode at most 1152 samples for
+ each call to lame_encode_buffer. see lame_encode_buffer() below
+ (LAME_MAXMP3BUFFER is now obsolete) */
+#define LAME_MAXMP3BUFFER (16384 + LAME_MAXALBUMART)
+
+
+typedef enum {
+ LAME_OKAY = 0,
+ LAME_NOERROR = 0,
+ LAME_GENERICERROR = -1,
+ LAME_NOMEM = -10,
+ LAME_BADBITRATE = -11,
+ LAME_BADSAMPFREQ = -12,
+ LAME_INTERNALERROR = -13,
+
+ FRONTEND_READERROR = -80,
+ FRONTEND_WRITEERROR = -81,
+ FRONTEND_FILETOOLARGE = -82
+
+} lame_errorcodes_t;
+
+#if defined(__cplusplus)
+}
+#endif
+#endif /* LAME_LAME_H */
+
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/lame/libmp3lame/lame_global_flags.h b/Src/Plugins/DSP/dsp_sc/sc2srclib/lame/libmp3lame/lame_global_flags.h
new file mode 100644
index 00000000..ad9e677d
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/lame/libmp3lame/lame_global_flags.h
@@ -0,0 +1,184 @@
+#ifndef LAME_GLOBAL_FLAGS_H
+#define LAME_GLOBAL_FLAGS_H
+
+#ifndef lame_internal_flags_defined
+#define lame_internal_flags_defined
+struct lame_internal_flags;
+typedef struct lame_internal_flags lame_internal_flags;
+#endif
+
+
+typedef enum short_block_e {
+ short_block_not_set = -1, /* allow LAME to decide */
+ short_block_allowed = 0, /* LAME may use them, even different block types for L/R */
+ short_block_coupled, /* LAME may use them, but always same block types in L/R */
+ short_block_dispensed, /* LAME will not use short blocks, long blocks only */
+ short_block_forced /* LAME will not use long blocks, short blocks only */
+} short_block_t;
+
+/***********************************************************************
+*
+* Control Parameters set by User. These parameters are here for
+* backwards compatibility with the old, non-shared lib API.
+* Please use the lame_set_variablename() functions below
+*
+*
+***********************************************************************/
+struct lame_global_struct {
+ unsigned int class_id;
+
+ /* input description */
+ unsigned long num_samples; /* number of samples. default=2^32-1 */
+ int num_channels; /* input number of channels. default=2 */
+ int samplerate_in; /* input_samp_rate in Hz. default=44.1 kHz */
+ int samplerate_out; /* output_samp_rate.
+ default: LAME picks best value
+ at least not used for MP3 decoding:
+ Remember 44.1 kHz MP3s and AC97 */
+ float scale; /* scale input by this amount before encoding
+ at least not used for MP3 decoding */
+ float scale_left; /* scale input of channel 0 (left) by this
+ amount before encoding */
+ float scale_right; /* scale input of channel 1 (right) by this
+ amount before encoding */
+
+ /* general control params */
+ int analysis; /* collect data for a MP3 frame analyzer? */
+ int write_lame_tag; /* add Xing VBR tag? */
+ int decode_only; /* use lame/mpglib to convert mp3 to wav */
+ int quality; /* quality setting 0=best, 9=worst default=5 */
+ MPEG_mode mode; /* see enum in lame.h
+ default = LAME picks best value */
+ int force_ms; /* force M/S mode. requires mode=1 */
+ int free_format; /* use free format? default=0 */
+ int findReplayGain; /* find the RG value? default=0 */
+ int decode_on_the_fly; /* decode on the fly? default=0 */
+ int write_id3tag_automatic; /* 1 (default) writes ID3 tags, 0 not */
+
+ int nogap_total;
+ int nogap_current;
+
+ int substep_shaping;
+ int noise_shaping;
+ int subblock_gain; /* 0 = no, 1 = yes */
+ int use_best_huffman; /* 0 = no. 1=outside loop 2=inside loop(slow) */
+
+ /*
+ * set either brate>0 or compression_ratio>0, LAME will compute
+ * the value of the variable not set.
+ * Default is compression_ratio = 11.025
+ */
+ int brate; /* bitrate */
+ float compression_ratio; /* sizeof(wav file)/sizeof(mp3 file) */
+
+
+ /* frame params */
+ int copyright; /* mark as copyright. default=0 */
+ int original; /* mark as original. default=1 */
+ int extension; /* the MP3 'private extension' bit.
+ Meaningless */
+ int emphasis; /* Input PCM is emphased PCM (for
+ instance from one of the rarely
+ emphased CDs), it is STRONGLY not
+ recommended to use this, because
+ psycho does not take it into account,
+ and last but not least many decoders
+ don't care about these bits */
+ int error_protection; /* use 2 bytes per frame for a CRC
+ checksum. default=0 */
+ int strict_ISO; /* enforce ISO spec as much as possible */
+
+ int disable_reservoir; /* use bit reservoir? */
+
+ /* quantization/noise shaping */
+ int quant_comp;
+ int quant_comp_short;
+ int experimentalY;
+ int experimentalZ;
+ int exp_nspsytune;
+
+ int preset;
+
+ /* VBR control */
+ vbr_mode VBR;
+ float VBR_q_frac; /* Range [0,...,1[ */
+ int VBR_q; /* Range [0,...,9] */
+ int VBR_mean_bitrate_kbps;
+ int VBR_min_bitrate_kbps;
+ int VBR_max_bitrate_kbps;
+ int VBR_hard_min; /* strictly enforce VBR_min_bitrate
+ normaly, it will be violated for analog
+ silence */
+
+
+ /* resampling and filtering */
+ int lowpassfreq; /* freq in Hz. 0=lame choses.
+ -1=no filter */
+ int highpassfreq; /* freq in Hz. 0=lame choses.
+ -1=no filter */
+ int lowpasswidth; /* freq width of filter, in Hz
+ (default=15%) */
+ int highpasswidth; /* freq width of filter, in Hz
+ (default=15%) */
+
+
+
+ /*
+ * psycho acoustics and other arguments which you should not change
+ * unless you know what you are doing
+ */
+ float maskingadjust;
+ float maskingadjust_short;
+ int ATHonly; /* only use ATH */
+ int ATHshort; /* only use ATH for short blocks */
+ int noATH; /* disable ATH */
+ int ATHtype; /* select ATH formula */
+ float ATHcurve; /* change ATH formula 4 shape */
+ float ATH_lower_db; /* lower ATH by this many db */
+ int athaa_type; /* select ATH auto-adjust scheme */
+ float athaa_sensitivity; /* dB, tune active region of auto-level */
+ short_block_t short_blocks;
+ int useTemporal; /* use temporal masking effect */
+ float interChRatio;
+ float msfix; /* Naoki's adjustment of Mid/Side maskings */
+
+ int tune; /* 0 off, 1 on */
+ float tune_value_a; /* used to pass values for debugging and stuff */
+
+ float attackthre; /* attack threshold for L/R/M channel */
+ float attackthre_s; /* attack threshold for S channel */
+
+
+ struct {
+ void (*msgf) (const char *format, va_list ap);
+ void (*debugf) (const char *format, va_list ap);
+ void (*errorf) (const char *format, va_list ap);
+ } report;
+
+ /************************************************************************/
+ /* internal variables, do not set... */
+ /* provided because they may be of use to calling application */
+ /************************************************************************/
+
+ int lame_allocated_gfp; /* is this struct owned by calling
+ program or lame? */
+
+
+
+ /**************************************************************************/
+ /* more internal variables are stored in this structure: */
+ /**************************************************************************/
+ lame_internal_flags *internal_flags;
+
+
+ struct {
+ int mmx;
+ int amd3dnow;
+ int sse;
+
+ } asm_optimizations;
+};
+
+int is_lame_global_flags_valid(const lame_global_flags * gfp);
+
+#endif /* LAME_GLOBAL_FLAGS_H */
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/shoutcast_output.cpp b/Src/Plugins/DSP/dsp_sc/sc2srclib/shoutcast_output.cpp
new file mode 100644
index 00000000..17e05b8b
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/shoutcast_output.cpp
@@ -0,0 +1,1636 @@
+#include <windows.h>
+#include <Ws2tcpip.h>
+#include "../api.h"
+#include "Include/shoutcast_output.h"
+#include "../../sc_serv3/nmrCommon/stl/stringUtils.h"
+#include "../utils.h"
+#include "../nu/ServiceBuilder.h"
+#include <winamp/dsp.h>
+
+#pragma intrinsic(memcpy, memset)
+
+static char buf[1024];
+static char out[1024];
+
+extern int iscompatibility;
+extern winampDSPModule module;
+extern api_service *WASABI_API_SVC;
+
+static api_connection *CreateConnection(const char *url)
+{
+ api_connection *conn = 0;
+ if (WASABI_API_SVC/*module.service*/)
+ {
+ if (!_strnicmp(url, "https://", 8))
+ {
+ ServiceBuild(WASABI_API_SVC/*module.service*/, conn, sslConnectionFactoryGUID);
+ }
+ else
+ {
+ ServiceBuild(WASABI_API_SVC/*module.service*/, conn, connectionFactoryGUID);
+ }
+ }
+
+ return conn;
+}
+
+static void ReleaseConnection(api_connection *&conn, const char *url)
+{
+ if (!conn) {
+ return;
+ }
+
+ waServiceFactory *connectionFactory = 0;
+ if (WASABI_API_SVC/*mod.service*/)
+ {
+ if (!_strnicmp(url, "https://", 8)) {
+ connectionFactory = WASABI_API_SVC/*mod.service*/->service_getServiceByGuid(sslConnectionFactoryGUID);
+ } else {
+ connectionFactory = WASABI_API_SVC/*mod.service*/->service_getServiceByGuid(connectionFactoryGUID);
+ }
+ }
+
+ if (connectionFactory) {
+ connectionFactory->releaseInterface(conn);
+ }
+
+ conn = 0;
+}
+
+int resolvenow(const char *hostname, unsigned short port, addrinfo **addr, int sockettype, char **saddress)
+{
+ addrinfo hints;
+ memset(&hints,0,sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ if (hostname)
+ hints.ai_flags = AI_NUMERICHOST;
+ else
+ hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
+ hints.ai_socktype = sockettype;
+
+ char portString[32] = {0};
+ sprintf(portString, "%u", (unsigned int)port);
+
+ if (getaddrinfo(hostname, portString, &hints, addr) == 0)
+ {
+ return 0;
+ }
+ else
+ {
+ hints.ai_flags = 0;
+ if (getaddrinfo(hostname, portString, &hints, addr) == 0)
+ {
+ // need to make sure we're not using 0.0.0.0
+ // as that will break us when using localhost
+ bool found = false;
+ struct addrinfo *ptr = NULL;
+ for (ptr = *addr; ptr != NULL; ptr = ptr->ai_next)
+ {
+ char* address = ::inet_ntoa(((sockaddr_in*)(ptr->ai_addr))->sin_addr);
+ if (strcmp(address, "0.0.0.0"))
+ {
+ *saddress = address;
+ *addr = ptr;
+ return 0;
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+void compatible_connect(T_OUTPUT *Output, int port) {
+
+ // due to a bug in re-using the connection
+ // with Winamp's jnetlib implementation we
+ // need to do a force drop and make a new
+ // instance so all is initialised properly
+ if (Output->Output && iscompatibility) {
+ Output->Output->Close();
+ Output->Output->Release();
+ Output->Output = NULL;
+ }
+
+ // create the connection only when it's needed
+ if (!Output->Output) {
+ Output->Output = CreateConnection("");
+ if (Output->Output) {
+ Output->Output->Open(API_DNS_AUTODNS, 16384, 16384);
+ }
+ }
+
+ if (Output->Output) {
+ if (iscompatibility && !strnicmp(Output->Config->Address, "localhost", 9)) {
+ addrinfo *saddr = 0;
+ char *address = 0;
+ if (!resolvenow(Output->Config->Address, (Output->Config->Port) + (LOBYTE(Output->Config->protocol) == 1), &saddr, SOCK_STREAM, &address) && address) {
+ Output->Output->connect(address, (Output->Config->Port) + (LOBYTE(Output->Config->protocol) == 1));
+ } else {
+ Output->Output->connect(Output->Config->Address, (Output->Config->Port) + (LOBYTE(Output->Config->protocol) == 1));
+ }
+ } else {
+ Output->Output->connect(Output->Config->Address, port);
+ }
+ }
+}
+
+SHOUTCAST_OUTPUT::SHOUTCAST_OUTPUT() : lame_init(0), lame_init_params(0), lame_encode_buffer_interleaved(0), lame_encode_flush(0), libinst(NULL) {
+ IOwnEncoder = 0;
+ SetEncoder(DEFAULT_ENCODER);
+ OutputManager.AddHandler(OUT_DISCONNECTED, Output_Disconnected);
+ OutputManager.AddHandler(OUT_CONNECT, Output_Connect);
+ OutputManager.AddHandler(OUT_REQUEST_CIPHER, Output_Request_Cipher);//cipher request
+ OutputManager.AddHandler(OUT_RECV_CIPHER, Output_Receive_Cipher);// and process cipher
+ OutputManager.AddHandler(OUT_SENDAUTH, Output_SendAuth);
+ OutputManager.AddHandler(OUT_RECVAUTHRESPONSE, Output_RecvAuthResponse);
+ OutputManager.AddHandler(OUT_SEND_MIME, Output_Send_Mime);
+ OutputManager.AddHandler(OUT_RECV_MIME, Output_Recv_Mime);
+ OutputManager.AddHandler(OUT_SEND_BITRATE, Output_Send_Bitrate);
+ OutputManager.AddHandler(OUT_RECV_BITRATE, Output_Recv_Bitrate);
+ OutputManager.AddHandler(OUT_SEND_BUFSIZE, Output_Send_Buf_Size);
+ OutputManager.AddHandler(OUT_RECV_BUFSIZE, Output_Recv_Buf_Size);
+ OutputManager.AddHandler(OUT_SEND_MAX, Output_Send_Max_Size);
+ OutputManager.AddHandler(OUT_RECV_MAX, Output_Recv_Max_Size);
+ OutputManager.AddHandler(OUT_SENDYP, Output_SendYP);
+ OutputManager.AddHandler(OUT_SEND_INITFLUSH, Output_Send_InitFlush);
+ OutputManager.AddHandler(OUT_RECV_INITFLUSH, Output_Recv_InitFlush);
+ OutputManager.AddHandler(OUT_SEND_INITSTANDBY, Output_Send_InitStandby);
+ OutputManager.AddHandler(OUT_RECV_INITSTANDBY, Output_Recv_InitStandby);
+ //OutputManager.AddHandler(OUT_SEND_INTRO, Output_Send_Intro);
+ //OutputManager.AddHandler(OUT_RECV_INTRO, Output_Recv_Intro);
+ //OutputManager.AddHandler(OUT_SEND_BACKUP, Output_Send_Backup);
+ //OutputManager.AddHandler(OUT_RECV_BACKUP, Output_Recv_Backup);
+ OutputManager.AddHandler(OUT_SENDCONTENT, Output_SendContent);
+ OutputManager.AddHandler(OUT_DISCONNECT, Output_Disconnect);
+ OutputManager.AddHandler(OUT_RECONNECT, Output_Reconnect);
+ OutputManager.AddHandler(OUT_TITLESENDUPDATE, Output_Title_SendUpdate);
+ OutputManager.AddHandler(OUT_SEND_METADATA, Output_Send_Metadata);
+ OutputManager.AddHandler(OUT_SEND_ARTWORK, Output_Send_Artwork);
+ ReleaseMutex((mutex = CreateMutex(NULL, TRUE, NULL)));
+}
+
+void SHOUTCAST_OUTPUT::SetLame(void *init, void *params, void *encode, void *finish) {
+ LOCK{
+ lame_init = (void (__cdecl *)(void))init;
+ lame_init_params = (void (__cdecl *)(lame_global_flags *))params;
+ lame_encode_buffer_interleaved = (int (__cdecl *)(lame_global_flags *, short int pcm[], int num_samples, char *mp3buffer, int mp3buffer_size))encode;
+ lame_encode_flush = (int (__cdecl *)(lame_global_flags *, char *mp3buffer, int size))finish;
+ }UNLOCK
+}
+
+SHOUTCAST_OUTPUT::~SHOUTCAST_OUTPUT() {
+ LOCK
+ CloseHandle(mutex);
+}
+
+/*
+Create a Uvox frame
+*/
+
+void SHOUTCAST_OUTPUT::createUvoxFrame(int length, char *payload_in, int type, T_OUTPUT *userData) {
+ int len = min(length, UV_MAX_DATA_LEN);
+ uv2xHdr hdr2 = { UV_SYNC_BYTE, UV_RESERVED, htons(type), htons(len), {UV_END}, UV_END };
+ if (payload_in && len > 0 && len <= UV_MAX_DATA_LEN) {
+ memcpy(hdr2.m_data, payload_in, len);
+ }
+ int sent = UV_HEADER_LEN + len + UV_END_LEN;
+ userData->Output->send(&hdr2, sent);
+ userData->Info.BytesSent += sent;
+}
+
+int SHOUTCAST_OUTPUT::createUvoxMetaFrame(int length, char *payload_in, int type,
+ T_OUTPUT *userData, unsigned short id,
+ unsigned short span) {
+ // check for the class type and abort if it's not right - will typically be 0x0000 or 0xXXFF
+ if ((type >= 0x3000) && (type < 0x5000)) {
+ int artType = ((type & 0xFF00) == (MSG_METADATA_ALBUMART|MSG_METADATA_PLAYING_ART));
+ int len = min(length, UV_MAX_META_LEN);
+ uv2xMetadataHdr metaHdr = { UV_SYNC_BYTE, UV_RESERVED, htons(type), htons(len + UV_META_LEN),
+ htons(id), htons(span), htons((span > 1 ? userData->Info.art_index[artType] : 0x1)),
+ {UV_END}, UV_END };
+
+ if (payload_in && len > 0 && len <= UV_MAX_META_LEN) {
+ memcpy(metaHdr.m_data, payload_in, len);
+ }
+
+ int sent = UV_HEADER_LEN + len + UV_META_LEN + UV_END_LEN;
+ if(userData->Output->send(&metaHdr, sent) != -1)
+ {
+ userData->Info.BytesSent += sent;
+ }
+ else
+ {
+ // if the send buffer is still full then we need to nudge
+ // it all along so that we can send the metadata as not
+ // checking for this will cause the loss of meta frames
+ while(userData->Output->GetSendBytesAvailable())
+ {
+ Sleep(10); // sleep a bit and try again
+ userData->Output->run();
+ if(userData->Output->send(&metaHdr, sent) != -1)
+ {
+ userData->Info.BytesSent += sent;
+ break;
+ }
+ }
+ }
+ return id+1;
+ }
+ return id;
+}
+
+/*
+Parse a Uvox Frame
+*/
+int SHOUTCAST_OUTPUT::parseUvoxFrame(char *payload_in, char *payload_out) {
+ LOCK{
+ uv2xHdr *hdr2 = (uv2xHdr *)payload_in;
+ int len = min(ntohs(hdr2->msgLen), UV_MAX_DATA_LEN);
+ memmove(payload_out, hdr2->m_data, len);
+ // just doing this to ensure its terminated correctly
+ hdr2->m_data[len] = UV_END;
+ }UNLOCK
+ return 1;
+}
+
+/*
+Check for known Uvox Error responses
+*/
+int SHOUTCAST_OUTPUT::checkUvoxFrameForError(char *pload_out, int state, T_OUTPUT *userData) {
+ LOCK{
+ if (userData->Info.Succeeded == -2 &&
+ userData->Info.ErrorMsg) {
+ free(userData->Info.ErrorMsg);
+ }
+ userData->Info.Succeeded = 1;
+ userData->Info.ErrorMsg = 0;
+
+ if (!strcmp("NAK:2.1:Deny", pload_out) || !strcmp("NAK:Deny", pload_out)) {
+ userData->Info.Succeeded = -1;
+ userData->Info.ErrorMsg = "NAK:Deny";
+ UNLOCK
+ return userData->Info.Succeeded;
+ }
+
+ if (!strcmp("NAK:2.1:Stream ID Error", pload_out)) {
+ userData->Info.Succeeded = -1;
+ userData->Info.ErrorMsg = "StreamID";
+ UNLOCK
+ return userData->Info.Succeeded;
+ }
+
+ if (!strcmp("NAK:2.1:Stream Moved", pload_out)) {
+ userData->Info.Succeeded = -1;
+ userData->Info.ErrorMsg = "StreamMoved";
+ UNLOCK
+ return userData->Info.Succeeded;
+ }
+
+ if (!strcmp("NAK:Bit Rate Error", pload_out)) {
+ userData->Info.Succeeded = -1;
+ userData->Info.ErrorMsg = "BitrateError";
+ UNLOCK
+ return userData->Info.Succeeded;
+ }
+
+ if (!strcmp("NAK:2.1:Version Error", pload_out)) {
+ userData->Info.Succeeded = -1;
+ userData->Info.ErrorMsg = "VersionError";
+ UNLOCK
+ return userData->Info.Succeeded;
+ }
+
+ if (!strcmp("NAK:2.1:Parse Error", pload_out) || !strcmp("NAK:Parse Error", pload_out)) {
+ userData->Info.Succeeded = -1;
+ userData->Info.ErrorMsg = "ParseError";
+ UNLOCK
+ return userData->Info.Succeeded;
+ }
+
+ if (!strcmp("NAK:Stream In Use", pload_out)) {
+ userData->Info.Succeeded = -1;
+ userData->Info.ErrorMsg = "InUse";
+ UNLOCK
+ return userData->Info.Succeeded;
+ }
+
+ if (!strcmp("NAK", pload_out)) {
+ userData->Info.Succeeded = -2;
+ // TODO
+ userData->Info.ErrorMsg = _strdup(pload_out);
+ UNLOCK
+ return userData->Info.Succeeded;
+ }
+
+ if (!strcmp("ACK", pload_out)) {
+ userData->Info.Succeeded = 1;
+ UNLOCK
+ return userData->Info.Succeeded;
+ }
+
+ }UNLOCK
+ return userData->Info.Succeeded;
+}
+
+int SHOUTCAST_OUTPUT::Run(int mode, void *Input, int InputSize, int SaveEncoder) {
+ int in_used = 0;
+ LOCK{
+ int bad = 1;
+
+ if (mode & OM_OTHER) OutputManager.Run(OutputManager.GetNumJobs());
+
+ for (int i = OutputManager.GetNumJobs()-1; i >= 0; i--) {
+ T_OUTPUT *Output = OutputManager[i];
+ if (mode & OM_OUTPUT && Output->Output) {
+ Output->Output->run();
+ }
+
+ int state = OutputManager.GetJobState(i);
+ if (state != OUT_DISCONNECTED) {
+ int outstate = (Output->Output ? Output->Output->get_state() : CONNECTION_STATE_ERROR);
+ if ((outstate == CONNECTION_STATE_ERROR || outstate == CONNECTION_STATE_CLOSED) &&
+ state != OUT_DISCONNECT && state != OUT_RECONNECT) {
+ if (Output->Type == OUTTYPE_SOURCE) {
+ Output->Info.ConnectionTime = clock();
+ Output->SlowClose = 0;
+ OutputManager.SetJobState(i, state = OUT_DISCONNECT); // kill the connection
+ } else if (Output->Type == OUTTYPE_TITLE) {
+ delete OutputManager[i];
+ OutputManager.DelJob(i); // title update failed, remove it
+ }
+ }
+ if (state == OUT_SENDCONTENT) bad = 0;
+ } else {
+ if (Output->Type == OUTTYPE_TITLE) {
+ #ifndef _DEBUG
+ delete OutputManager[i];
+ #endif
+ OutputManager.DelJob(i); // title update succeeded, remove it
+ }
+ }
+ }// for num jobs
+ if (!bad && Input && (InputSize > 0) && Encoder && (mode & OM_ENCODE)) {
+ while (in_used < InputSize && InputSize > 0) {
+ int inused = 0;
+ char EncodedData[32768] = {0};
+ int out_used = Encoder->Encode(((char *)Input+in_used), (InputSize-in_used), EncodedData, sizeof(EncodedData), &inused);
+ in_used += inused;
+
+ for (int i = OutputManager.GetNumJobs()-1; i >= 0; i--) {
+ T_OUTPUT *Output = OutputManager[i];
+ int state = OutputManager.GetJobState(i);
+ if (out_used > 0 && state == OUT_SENDCONTENT) {
+ int sofar = 0, type = 0;
+
+ // when enabled this will save the encoded output to a local file for DJ backup, etc
+ if (SaveEncoder != -1) {
+ WriteSaveEncoded(SaveEncoder, EncodedData, out_used);
+ }
+
+ if (strcmp("audio/aacp", Output->ContentType)==0) { type = AACP_DATA; } // aacp
+ if (strcmp("audio/aac", Output->ContentType)==0) { type = AAC_LC_DATA; } // aac lc
+ if (strcmp("audio/mpeg", Output->ContentType)==0) { type = MP3_DATA; } // mp3
+ if (strcmp("audio/ogg", Output->ContentType)==0) { type = OGG_DATA; } // ogg
+
+ // make sure that this doesn't go negative otherwise things will go wrong
+ while (out_used > 0) {
+ int delta = Output->Output->GetSendBytesAvailable();
+
+ if (LOBYTE(Output->Config->protocol) != 1) {
+ // try to clamp things so that it's within the packet size limits
+ delta = min(delta, UV_MAX_DATA_LEN);
+ }
+
+ delta = min(delta, out_used);
+ if (delta > 7) {
+ if (LOBYTE(Output->Config->protocol) != 1) {
+ // send sc2 data frames
+ createUvoxFrame(delta, EncodedData+sofar, type, Output);
+ } else {
+ // send sc1 data
+ Output->Info.BytesSent += delta;
+ Output->Output->send(EncodedData+sofar, delta);
+ }
+ } else {
+ // check for the connection having dropped and we're just spinning
+ // and if we are then we need to abort from here else we lock up
+ int outstate = Output->Output->get_state();
+ if (outstate == CONNECTION_STATE_CLOSED || outstate == CONNECTION_STATE_ERROR) {
+ break;
+ }
+ Sleep(10); // sleep a bit and try again
+ Output->Output->run();
+ }
+ sofar+=delta;
+ out_used-=delta;
+ }
+ }
+ }
+ if (InputSize <= 0) break;
+ }
+ }
+ }UNLOCK
+ return in_used;
+}
+
+int SHOUTCAST_OUTPUT::AddOutput(int Connection, T_OUTPUT_CONFIG *Config, void (*TitleCallback)(const int Connection, const int Mode)) {
+ if (Connection >= 0 && Connection < 5) {
+ T_OUTPUT *job = new T_OUTPUT;
+ job->Bitrate = 0;
+ job->ContentType = "audio/mpeg";
+ if (Encoder) {
+ int infosize = sizeof(T_EncoderIOVals);
+ T_EncoderIOVals *EncSettings = (T_EncoderIOVals *)Encoder->GetExtInfo(&infosize);
+ if (EncSettings && infosize) job->Bitrate = EncSettings->output_bitRate;
+ job->ContentType = Encoder->GetContentType();
+ }
+ job->Connection = Connection;
+ job->TitleCallback = TitleCallback;
+ job->Config = Config;
+ job->Info.Reconnect = Config->AutoRecon;
+ job->Info.ReconnectTime = Config->ReconTime;
+ job->Type = OUTTYPE_SOURCE;
+ job->SlowClose = 0;
+ // trigger a title update on start as artwork
+ // is done later so does not need to set here
+ job->Info.meta_cached = 1;
+
+ int retval = -1;
+ LOCK{
+ retval = OutputManager.AddJob(OUT_DISCONNECTED, job);
+ }UNLOCK
+ return retval;
+ }
+ return -1;
+}
+
+void SHOUTCAST_OUTPUT::UpdateOutput(int Connection) {
+ if (Connection >= 0 && Connection < 5) {
+ LOCK{
+ T_OUTPUT *Output = OutputManager[Connection];
+ if (Output) {
+ Output->Info.Reconnect = Output->Config->AutoRecon;
+ Output->Info.ReconnectTime = Output->Config->ReconTime;
+ }
+ }UNLOCK
+ }
+}
+
+void SHOUTCAST_OUTPUT::RemoveOutput(int Connection) {
+ if (Connection >= 0 && Connection < 5) {
+ LOCK{
+ T_OUTPUT *Output = OutputManager[Connection];
+ if (Output) {
+ OutputManager.DelJob(Connection);
+ delete Output;
+ }
+ }UNLOCK
+ }
+}
+
+int SHOUTCAST_OUTPUT::ConnectOutput(int Connection) {
+ if (Connection >= 0 && Connection < 5) {
+ LOCK{
+ T_OUTPUT *Output = OutputManager[Connection];
+ if (Output && Encoder) {
+ UpdateOutput(Connection);
+
+ compatible_connect(Output, (Output->Config->Port) + (LOBYTE(Output->Config->protocol) == 1));
+
+ Output->Bitrate = 0;
+ Output->ContentType = "audio/mpeg";
+
+ if (Encoder) {
+ int infosize = sizeof(T_EncoderIOVals);
+ T_ENCODER_MP3_INFO *EncSettings = (T_ENCODER_MP3_INFO *)Encoder->GetExtInfo(&infosize);
+ if (EncSettings && infosize) Output->Bitrate = EncSettings->output_bitRate;
+ Output->ContentType = Encoder->GetContentType();
+ }
+ OutputManager.SetJobState(Connection, OUT_CONNECT);
+ }
+ }UNLOCK
+ }
+ return 1;
+}
+
+int SHOUTCAST_OUTPUT::DisconnectOutput(int Connection, int withReconnect, int reconnectTime) {
+ if (Connection >= 0 && Connection < 5) {
+ LOCK{
+ T_OUTPUT *Output = OutputManager[Connection];
+ if (Output) {
+ int state = OutputManager.GetJobState(Connection);
+ if (state != OUT_DISCONNECTED) {
+ Output->Info.Reconnect = withReconnect >= 0 ? withReconnect : Output->Config->AutoRecon;
+ Output->Info.ReconnectTime = reconnectTime >= 0 ? reconnectTime : Output->Config->ReconTime;
+ Output->SlowClose = 0;
+ if (Encoder) {
+ int infosize = sizeof(T_EncoderIOVals);
+ T_ENCODER_MP3_INFO *EncSettings = (T_ENCODER_MP3_INFO *)Encoder->GetExtInfo(&infosize);
+ if (EncSettings && infosize) Output->Bitrate = EncSettings->output_bitRate;
+ Output->ContentType = Encoder->GetContentType();
+ }
+ OutputManager.SetJobState(Connection, OUT_DISCONNECT);
+ }
+ }
+ }UNLOCK
+ }
+ return 1;
+}
+
+void SHOUTCAST_OUTPUT::SetEncoder(C_ENCODER *encoder, int takeOwnership) {
+ LOCK{
+ if (IOwnEncoder && Encoder && Encoder != DEFAULT_ENCODER)
+ delete Encoder;
+ if (encoder != DEFAULT_ENCODER) {
+ IOwnEncoder = takeOwnership;
+ Encoder = encoder;
+ } else {
+ try {
+ Encoder = new C_ENCODER_MP3(lame_init, lame_init_params, lame_encode_buffer_interleaved, lame_encode_flush);
+ IOwnEncoder = 1;
+ } catch(...) {
+ Encoder = NULL;
+ }
+ }
+ }UNLOCK
+}
+
+C_ENCODER *SHOUTCAST_OUTPUT::GetEncoder() {
+ C_ENCODER *Enc = NULL;
+ LOCK{
+ Enc = Encoder;
+ }UNLOCK
+ return Enc;
+}
+
+bool validateTitle(wchar_t **dest, const wchar_t* src)
+{
+ bool allowed = true;
+ int src_len = lstrlenW(src);
+ char *str = (char*)calloc(src_len, sizeof(char));
+ if (str)
+ {
+ WideCharToMultiByte(CP_ACP, 0, src, -1, str, src_len, 0, 0);
+
+ std::string updinfoSong(str);
+ if (!stringUtil::stripAlphaDigit(updinfoSong).empty())
+ {
+ // work on lowercase comparison as well as doing a check to see if
+ // after removing white space + punctuation we have a valid title.
+ std::string m_checkUpdinfoSong = stringUtil::toLower(updinfoSong);
+
+ // exclude weird title updates from being accepted
+ // as no point in giving junk to the user later on
+ if (m_checkUpdinfoSong.find("!doctype") != string::npos ||
+ m_checkUpdinfoSong.find("<script") != string::npos ||
+ m_checkUpdinfoSong.find("<html") != string::npos ||
+ m_checkUpdinfoSong.find("<body") != string::npos ||
+ m_checkUpdinfoSong.find("<div") != string::npos ||
+ m_checkUpdinfoSong.find("%] ") != string::npos ||
+ m_checkUpdinfoSong.find("invalid resource") != string::npos ||
+ (m_checkUpdinfoSong.find("nextsong") != string::npos &&
+ m_checkUpdinfoSong.find("sctrans2next") != string::npos) ||
+
+ m_checkUpdinfoSong.find("radio online") != string::npos ||
+
+ m_checkUpdinfoSong.find("track ") == 0 ||
+ m_checkUpdinfoSong.find("track0") == 0 ||
+ m_checkUpdinfoSong.find("track1") == 0 ||
+ m_checkUpdinfoSong.find("stream ") == 0 ||
+ m_checkUpdinfoSong.find("no artist ") == 0 ||
+ m_checkUpdinfoSong.find("new artist ") == 0 ||
+ m_checkUpdinfoSong.find("line-in ") == 0 ||
+ m_checkUpdinfoSong.find("inter_") == 0 ||
+ m_checkUpdinfoSong.find("jj mckay - ") == 0 ||
+ m_checkUpdinfoSong.find("artist - ") == 0 ||
+
+ m_checkUpdinfoSong.find("$") == 0 ||
+ m_checkUpdinfoSong.find("%") == 0 ||
+ m_checkUpdinfoSong.find("&") == 0 ||
+ m_checkUpdinfoSong.find("[") == 0 ||
+ m_checkUpdinfoSong.find("?") == 0 ||
+ m_checkUpdinfoSong.find("_") == 0 ||
+ m_checkUpdinfoSong.find("- ") == 0 ||
+ m_checkUpdinfoSong.find(". ") == 0 ||
+
+ m_checkUpdinfoSong == "-" ||
+ m_checkUpdinfoSong == "auto dj" ||
+ m_checkUpdinfoSong == "ao vivo" ||
+ m_checkUpdinfoSong == "unknown" ||
+ m_checkUpdinfoSong == "test" ||
+ m_checkUpdinfoSong == "dsp" ||
+ m_checkUpdinfoSong == "demo" ||
+ m_checkUpdinfoSong == "line input" ||
+ m_checkUpdinfoSong == "dj mike llama - llama whippin` intro" ||
+ m_checkUpdinfoSong == "preview") {
+ allowed = false;
+ }
+ }
+ else
+ {
+ allowed = false;
+ }
+ }
+ else
+ {
+ allowed = false;
+ }
+
+ if (dest) {
+ if (*dest)
+ {
+ free(*dest);
+ }
+ *dest = _wcsdup(allowed ? src : L"");
+ }
+
+ return allowed;
+}
+
+void SHOUTCAST_OUTPUT::UpdateTitleCache(wchar_t *Title, std::vector<std::wstring> NextList, wchar_t *Song,
+ wchar_t *Album, wchar_t *Artist, wchar_t *Genre, wchar_t *Comment,
+ wchar_t* Year, int Connection, bool sendNext) {
+ int update = 0;
+
+ if(!metadata.Title || wcscmp(metadata.Title, Title)) {
+ if (metadata.Title) free(metadata.Title);
+ metadata.Title = _wcsdup(Title);
+ update++;
+ }
+
+ metadata.NextList.resize(0);
+ if (!NextList.empty()) {
+ metadata.NextList = NextList;
+ update++;
+ }
+
+ if(!metadata.Song || wcscmp(metadata.Song, (Song ? Song : L""))) {
+ if (validateTitle(&metadata.Song, (Song ? Song : L""))) {
+ update++;
+ }
+ }
+
+ if(!metadata.Album || wcscmp(metadata.Album, (Album ? Album : L""))) {
+ if (validateTitle(&metadata.Album, (Album ? Album : L""))) {
+ update++;
+ }
+ }
+
+ if(!metadata.Artist || wcscmp(metadata.Artist, (Artist ? Artist : L""))) {
+ if (validateTitle(&metadata.Artist, (Artist ? Artist : L""))) {
+ update++;
+ }
+ }
+
+ if(!metadata.Genre || wcscmp(metadata.Genre, (Genre ? Genre : L""))) {
+ if (validateTitle(&metadata.Genre, (Genre ? Genre : L""))) {
+ update++;
+ }
+ }
+
+ if(!metadata.Comment || wcscmp(metadata.Comment, (Comment ? Comment : L""))) {
+ if (validateTitle(&metadata.Comment, (Comment ? Comment : L""))) {
+ update++;
+ }
+ }
+
+ if(!metadata.Year || wcscmp(metadata.Year, (Year ? Year : L""))) {
+ if (validateTitle(&metadata.Year, (Year ? Year : L""))) {
+ update++;
+ }
+ }
+
+ UpdateTitle(0, NextList, Connection, sendNext);
+}
+
+void SHOUTCAST_OUTPUT::UpdateAlbumArtCache(void* APIC, int APICLength, int APICType, int Connection) {
+ int artType = ((APICType & 0xFF00) == (MSG_METADATA_ALBUMART|MSG_METADATA_PLAYING_ART));
+ // make sure we're within the metadata limits
+ // which is 32 * max metadata payload (523872)
+ // and if not then we discard the artwork
+ int prevAPICLength = metadata.APICLength[artType];
+ if (APICLength > UV_MAX_TOTAL_META_LEN) {
+ metadata.APICLength[artType] = 0;
+ metadata.APIC[artType] = 0;
+ } else {
+ metadata.APIC[artType] = APIC;
+ metadata.APICLength[artType] = APICLength;
+ }
+ metadata.APICType[artType] = APICType;
+
+ // update the metadata cache usage so we can work
+ if (Connection >= 0 && Connection < 5) {
+ LOCK{
+ T_OUTPUT *Output = OutputManager[Connection];
+ if (Output) {
+ // only update the flag if it's new stream art or is playing and is different from before
+ if (!(!prevAPICLength && artType && (prevAPICLength == metadata.APICLength[artType]))) {
+ Output->Info.meta_cached |= (!artType ? 2 : 4);
+ }
+ }
+ }UNLOCK
+
+ UpdateArtwork(Connection);
+ }
+}
+
+void SHOUTCAST_OUTPUT::UpdateTitle(wchar_t *Title, std::vector<std::wstring> NextList,
+ int Connection, bool sendNext, bool UseCache) {
+ //LOCK{
+ if (Connection >= 0 && Connection < 5) {
+ T_OUTPUT *Output = OutputManager[Connection];
+ if (Output && Output->Type == OUTTYPE_SOURCE &&
+ (OutputManager.GetJobState(Connection) == OUT_SENDCONTENT ||
+ OutputManager.GetJobState(Connection) == OUT_SEND_METADATA)) {
+
+ // clear the metadata send flag
+ if (Output->Info.meta_cached & 1) {
+ Output->Info.meta_cached -= 1;
+ }
+
+ if (LOBYTE(Output->Config->protocol) == 1 && Output->Config->doTitleUpdate) {
+ T_OUTPUT *job = new T_OUTPUT;
+ job->Bitrate = Output->Bitrate;
+ job->ContentType = Encoder->GetContentType();
+ job->Config = Output->Config;
+ job->Type = OUTTYPE_TITLE;
+ job->SlowClose = 0;
+ compatible_connect(job, job->Config->Port);
+
+ wchar_t *title = (UseCache?metadata.Title:Title);
+ if (title) {
+ validateTitle(&job->Info.Title, title);
+ validateTitle(&Output->Info.Title, title);
+ } else {
+ validateTitle(&job->Info.Title, Output->Info.Title);
+ }
+
+ OutputManager.AddJob(OUT_CONNECT, job);
+ } else if (LOBYTE(Output->Config->protocol) != 1) {
+ validateTitle(&Output->Info.Title, (UseCache?metadata.Title:Title));
+
+ //#ifndef _DEBUG
+ if (UseCache) {
+ if (!metadata.NextList.empty()) {
+ Output->Info.NextList = metadata.NextList;
+ }
+ } else {
+ if (!NextList.empty()) {
+ Output->Info.NextList = NextList;
+ }
+ }
+ //#endif
+
+ validateTitle(&Output->Info.Song, (metadata.Song && UseCache ? metadata.Song : L""));
+ validateTitle(&Output->Info.Album, (metadata.Album && UseCache ? metadata.Album : L""));
+ validateTitle(&Output->Info.Artist, (metadata.Artist && UseCache ? metadata.Artist : L""));
+ validateTitle(&Output->Info.Genre, (metadata.Genre ? metadata.Genre : L""));
+ validateTitle(&Output->Info.Comment, (metadata.Comment && UseCache ? metadata.Comment : L""));
+ validateTitle(&Output->Info.Year, (metadata.Year && UseCache ? metadata.Year : L""));
+
+ if (Output->Config->doTitleUpdate) {
+ // only output friendlier line breaks when debugging is needed
+ #ifdef _DEBUG
+ #define XML_DEBUG
+ #endif
+
+ #ifdef XML_DEBUG
+ #define EOL "\n"
+ #define TAB "\t"
+ #else
+ #define EOL ""
+ #define TAB ""
+ #endif
+ stringstream s;
+ s << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<metadata>" EOL;
+
+ wchar_t * title = (Output->Info.Song && *Output->Info.Song ? Output->Info.Song : Output->Info.Title);
+ if (validateTitle(0, title)) {
+ s << "<TIT2>" << ConvertToUTF8Escaped(title) << "</TIT2>" EOL;
+ }
+
+ if (Output->Info.Album && Output->Info.Album[0]) s << "<TALB>" << ConvertToUTF8Escaped(Output->Info.Album) << "</TALB>" EOL;
+ if (Output->Info.Artist && Output->Info.Artist[0]) s << "<TPE1>" << ConvertToUTF8Escaped(Output->Info.Artist) << "</TPE1>" EOL;
+ if (Output->Info.Year && Output->Info.Year[0]) s << "<TYER>" << ConvertToUTF8Escaped(Output->Info.Year) << "</TYER>" EOL;
+ if (Output->Info.Comment && Output->Info.Comment[0]) s << "<COMM>" << ConvertToUTF8Escaped(Output->Info.Comment) << "</COMM>" EOL;
+ if (Output->Info.Genre && Output->Info.Genre[0]) s << "<TCON>" << ConvertToUTF8Escaped(Output->Info.Genre) << "</TCON>" EOL;
+
+ s << "<TENC>SHOUTcast Source DSP v" << sourceVersion << "</TENC>" EOL;
+
+ if (Output->Config->Description[0]) s << "<TRSN>" << escapeXML(Output->Config->Description) << "</TRSN>" EOL;
+
+ s << "<WORS>" << escapeXML(Output->Config->ServerURL && Output->Config->ServerURL[0] ? Output->Config->ServerURL : "http://www.shoutcast.com") << "</WORS>" EOL;
+
+ if (validateTitle(0, title)) {
+ s << "<extension>" EOL TAB "<TITLE seq=\"1\">" << ConvertToUTF8Escaped(title) << "</TITLE>" EOL;
+
+ if (!Output->Info.NextList.empty() && sendNext) {
+ s << TAB;
+ std::string soon;
+ for (size_t idx = 0, seq = 0; idx < Output->Info.NextList.size(); idx++) {
+ if (validateTitle(0, Output->Info.NextList[idx].c_str()))
+ {
+ std::string next = ConvertToUTF8Escaped(Output->Info.NextList[idx].c_str());
+ s << "<TITLE seq=\"" << (seq+2) << "\">" << next << "</TITLE>" EOL TAB;
+ // store the first item as that is used for the 'soon' item
+ if (seq == 0) soon = next;
+ seq++;
+ }
+ }
+ if (!soon.empty()) {
+ s << "<soon>" << soon << "</soon>" EOL;
+ }
+ }
+ s << "</extension>" EOL;
+ }
+ s << "</metadata>";
+
+ // TODO make sure this will split up > UV_MAX_META_FRAME_LEN blocks
+ mid = createUvoxMetaFrame(s.str().length(),(char*)s.str().data(), MSG_METADATA_XML_NEW, Output, mid);
+ }
+ }
+ }
+ }
+}
+
+void SHOUTCAST_OUTPUT::UpdateArtwork(int Connection) {
+ if (Connection >= 0 && Connection < 5) {
+ LOCK{
+ T_OUTPUT *Output = OutputManager[Connection];
+ if (Output && Output->Type == OUTTYPE_SOURCE) {
+
+ if (LOBYTE(Output->Config->protocol) != 1) {
+ Output->Info.APIC[0] = metadata.APIC[0];
+ Output->Info.APICLength[0] = metadata.APICLength[0];
+ Output->Info.APICType[0] = metadata.APICType[0];
+
+ Output->Info.APIC[1] = metadata.APIC[1];
+ Output->Info.APICLength[1] = metadata.APICLength[1];
+ Output->Info.APICType[1] = metadata.APICType[1];
+
+ // calculate the album art span inorder to use it once we've sent the title in following callbacks
+ for (int i = 0; i < 2; i++) {
+ int AlbumArtSpan = (metadata.APICLength[i] / UV_MAX_DATA_LEN) + ((metadata.APICLength[i] % UV_MAX_DATA_LEN) < UV_MAX_DATA_LEN ? 1 : 0);
+ // if over the limit then abort trying to send this
+ if (AlbumArtSpan > UV_MAX_META_FRAGMENTS) {
+ AlbumArtSpan = 1;
+ Output->Info.APIC[i] = 0;
+ }
+
+ Output->Info.art_cached_span[i] = Output->Info.art_cached[i] = AlbumArtSpan;
+ Output->Info.art_index[i] = 1;
+ Output->Info.art_cached_length[i] = Output->Info.APICLength[i];
+ }
+ }
+ }
+ }UNLOCK
+ }
+}
+
+int SHOUTCAST_OUTPUT::UpdateAlbumArt(int Connection) {
+ if (Connection >= 0 && Connection < 5) {
+ LOCK{
+ T_OUTPUT *Output = OutputManager[Connection];
+ if (Output && Output->Type == OUTTYPE_SOURCE &&
+ OutputManager.GetJobState(Connection) == OUT_SEND_ARTWORK) {
+ int artType = (Output->Info.meta_cached & 4 ? 1 : (Output->Info.meta_cached & 2 ? 0 : -1));
+ if (artType != -1 && LOBYTE(Output->Config->protocol) != 1 && Output->Info.art_cached[artType] > 0) {
+ int type = Output->Info.APICType[artType];
+ int length = Output->Info.art_cached_length[artType];
+ int count = Output->Info.art_cached_span[artType] - Output->Info.art_cached[artType];
+
+ // attempt to process as a multi-part message as APIC most likely won't fit in just one uvox packet
+ if (length >= UV_MAX_META_LEN) {
+ createUvoxMetaFrame(UV_MAX_META_LEN,
+ (char*)Output->Info.APIC[artType]+(count * UV_MAX_META_LEN),
+ type, Output, mid, Output->Info.art_cached_span[artType]);
+ Output->Info.art_cached_length[artType] -= UV_MAX_META_LEN;
+ } else {
+ createUvoxMetaFrame(length,
+ (char*)Output->Info.APIC[artType]+(count * UV_MAX_META_LEN),
+ type, Output, mid, Output->Info.art_cached_span[artType]);
+ Output->Info.art_cached_length[artType] = 0;
+ }
+ Output->Info.art_index[artType] += 1;
+
+ if (Output->Info.art_cached[artType] == 1) {
+ mid+=1;
+ Output->Info.meta_cached -= (artType ? 4 : 2);
+ // reset the values so we can re-send on disconnect, etc
+ Output->Info.art_cached[artType] = Output->Info.art_cached_span[artType];
+ Output->Info.art_index[artType] = 1;
+ Output->Info.art_cached_length[artType] = Output->Info.APICLength[artType];
+ }
+ }
+ }
+ }UNLOCK
+ }
+ return 1;
+}
+
+enum OUTPUTSTATE SHOUTCAST_OUTPUT::GetState(int Connection) {
+ int retval = -1;
+ if (Connection >= 0 && Connection < 5) {
+ LOCK{
+ retval = OutputManager.GetJobState(Connection);
+ }UNLOCK
+ }
+ return retval == -1 ? OUT_ERROR : (enum OUTPUTSTATE)retval;
+}
+
+T_OUTPUT_CONFIG *SHOUTCAST_OUTPUT::operator[](int Connection) {
+ return GetOutput(Connection);
+}
+
+T_OUTPUT_CONFIG *SHOUTCAST_OUTPUT::GetOutput(int Connection) {
+ T_OUTPUT_CONFIG *Config = NULL;
+ if (Connection >= 0 && Connection < 5) {
+ LOCK{
+ T_OUTPUT *Output = OutputManager[Connection];
+ if (Output) Config = Output->Config;
+ }UNLOCK
+ }
+ return Config;
+}
+
+T_OUTPUT_INFO *SHOUTCAST_OUTPUT::GetOutputInfo(int Connection) {
+ T_OUTPUT_INFO *Info = NULL;
+ if (Connection >= 0 && Connection < 5) {
+ LOCK{
+ T_OUTPUT *Output = OutputManager[Connection];
+ if (Output) Info = &Output->Info;
+ }UNLOCK
+ }
+ return Info;
+}
+
+// Protected methods
+
+int SHOUTCAST_OUTPUT::Output_Disconnected(int state, int last_state, T_OUTPUT *userData) {
+ STATE;
+ LOCK{
+ userData->Config->protocol_retry = 0;
+ }UNLOCK
+ return state; // sit and spin
+}
+
+int SHOUTCAST_OUTPUT::Output_Connect(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ userData->Config->protocol_retry = MAKEWORD(0, HIBYTE(userData->Config->protocol_retry));
+ userData->Info.Succeeded = 1;
+ if (userData->Output) {
+ userData->Output->FlushSend();
+ }
+
+ if ((clock() - userData->Info.ConnectionTime) / CLOCKS_PER_SEC >= 1/*userData->Info.ReconnectTime*/) {
+ if (userData->Output && userData->Output->get_state() == CONNECTION_STATE_CONNECTED) { // are we connected yet?
+ userData->Info.ConnectionTime = clock();
+ if (userData->Type == OUTTYPE_SOURCE) {
+ userData->Info.Reconnect = userData->Config->AutoRecon;
+ userData->Info.ReconnectTime = userData->Config->ReconTime;
+ userData->Info.ConnectedAt = time(NULL);
+ UNLOCK
+ return OUT_REQUEST_CIPHER; // connected, go authenticate
+ } else if (userData->Type == OUTTYPE_TITLE) {
+ UNLOCK
+ return OUT_TITLESENDUPDATE; // connected, go update the title
+ }
+ }
+ }
+ }UNLOCK
+ return state; // sit and spin
+}
+
+int SHOUTCAST_OUTPUT::Output_SendContent(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ if (userData->Output->get_state() == CONNECTION_STATE_ERROR) { // connection error?
+ return OUT_DISCONNECT; // error happened, go shut down
+ }
+
+ // check if we have any metadata or artwork to dispatch (depends on protocol)
+ if (userData->Info.meta_cached & 1) {
+ userData->Info.meta_cached -= 1;
+ return OUT_SEND_METADATA;
+ } else if (LOBYTE(userData->Config->protocol) != 1 &&
+ (userData->Info.meta_cached & 2 || userData->Info.meta_cached & 4) &&
+ userData->Info.art_cached > 0) {
+ return OUT_SEND_ARTWORK;
+ }
+
+ return state; // sit and spin
+}
+
+int SHOUTCAST_OUTPUT::Output_Disconnect(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ //STATE;
+ LOCK{
+ // reset the metadata flags so it will trigger on a connection coming back
+ // with usage of what was already cached to determine what we will re-send
+ userData->Info.meta_cached = 1|(userData->Info.art_cached_length[0] ? 2 : 0)|(userData->Info.art_cached_length[1] ? 4 : 0);
+
+ int outstate = (userData->Output ? userData->Output->get_state() : CONNECTION_STATE_ERROR);
+ if (outstate == CONNECTION_STATE_CONNECTING) { // are we connecting? if so then just abort
+ UNLOCK
+ return OUT_DISCONNECTED;
+ }
+
+ if (outstate == CONNECTION_STATE_CONNECTED) { // are we connected yet?
+ userData->Info.ConnectionTime = clock();
+ userData->Info.ConnectedAt = 0;
+ userData->Info.BytesSent = 0;
+ if (LOBYTE(userData->Config->protocol) != 1) {
+ createUvoxFrame(1, "0\0", MSG_TERMINATE, userData);
+ if (userData->Info.Succeeded != -1) {
+ Output_DUMMY(state, last_state, userData);
+ }
+ }
+ userData->Output->Close(!userData->SlowClose);
+ }
+
+ if (outstate == CONNECTION_STATE_CLOSING) {
+ userData->Info.ConnectionTime = clock(); // update the clock with the current time so that we don't get some weird crap for reconnections.
+ }
+
+ if (outstate == CONNECTION_STATE_CLOSED || outstate == CONNECTION_STATE_ERROR) {
+ userData->Info.Switching = 0;
+ if (last_state == OUT_SENDYP) {
+ userData->Info.Succeeded = -1;
+ userData->Info.ErrorMsg = "Blocked";
+ } else if (userData->Type == OUTTYPE_SOURCE &&
+ (last_state == OUT_CONNECT || last_state == OUT_REQUEST_CIPHER ||
+ last_state == OUT_SENDAUTH || last_state == OUT_RECV_CIPHER ||
+ last_state == OUT_DISCONNECT)) {
+ // if using automatic mode then switch between v1 and v2 modes as needed
+ if (HIBYTE(userData->Config->protocol) && ((LOBYTE(userData->Config->protocol_retry) > 5) ||
+ (last_state == OUT_CONNECT && HIBYTE(userData->Config->protocol_retry) < 1))) {
+ int protocol = (2 - (LOBYTE(userData->Config->protocol) != 1));
+ userData->Config->protocol_retry = MAKEWORD(0, HIBYTE(userData->Config->protocol_retry)+1);
+ userData->Info.Switching = (LOBYTE(userData->Config->protocol) != 1 ? 2 : 1);
+ userData->Config->protocol = MAKEWORD(protocol, 1);
+ userData->Info.ConnectionTime = clock();
+ UNLOCK
+ return OUT_RECONNECT;
+ }
+ }
+
+ if (userData->Info.Reconnect && userData->Type == OUTTYPE_SOURCE) {
+ // if using automatic mode then switch between v1 and v2 modes as needed
+ if (HIBYTE(userData->Config->protocol)) {
+ // TODO need to make this into a function and have it show the switching message
+ int protocol = (2 - (LOBYTE(userData->Config->protocol) != 1));
+ userData->Config->protocol_retry = 0;
+ userData->Info.Switching = (LOBYTE(userData->Config->protocol) != 1 ? 2 : 1);
+ userData->Config->protocol = MAKEWORD(protocol, 1);
+ userData->Info.ConnectionTime = clock();
+ }
+ UNLOCK
+ return OUT_RECONNECT;
+ } else {
+ UNLOCK
+ return OUT_DISCONNECTED;
+ }
+ }
+ }UNLOCK
+ return state; // sit and spin
+}
+
+int SHOUTCAST_OUTPUT::Output_Reconnect(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ if ((clock() - userData->Info.ConnectionTime) / CLOCKS_PER_SEC >= userData->Info.ReconnectTime) {
+ if (userData->Output) {
+ compatible_connect(userData, userData->Config->Port + (LOBYTE(userData->Config->protocol) == 1));
+ }
+ UNLOCK
+ return OUT_CONNECT;
+ }
+ }UNLOCK
+ return state; // sit and spin
+}
+
+void FixString(const char *in, char *out) {
+ while (in && *in) {
+ if ((*in >= 'A' && *in <= 'Z') ||
+ (*in >= 'a' && *in <= 'z') ||
+ (*in >= '0' && *in <= '9') ||
+ (*in == '-') ||
+ (*in == '_') ||
+ (*in == '.') ||
+ (*in == '!') ||
+ (*in == '~') ||
+ (*in == '*') ||
+ (*in == '\'') ||
+ (*in == '(') ||
+ (*in == '[') ||
+ (*in == ']') ||
+ (*in == ')')) {
+ *out++=*in++;
+ } else if (*in >= 0 && *in < 32 && *in != 9 && *in != 10 && *in != 13) {
+ // strip out characters which aren't supported by the DNAS
+ // (only allow backspace, linefeed and carriage return)
+ in++;
+ } else {
+ unsigned int i=*(unsigned char *)in;
+ const char *t=in;
+ in++;
+ if (in == t + 1) {
+ if (i == '\'') i = '`';
+ else if (i == '<') i = '(';
+ else if (i == '>') i = ')';
+ else if (i == '\"') i='`';
+ else if (i == '[') i='`';
+ else if (i == ']') i='`';
+ snprintf(out, 3, "%%%02X", i);
+ out += 3;
+ } else if (in == t + 2) { // multibyte
+ }
+ }
+ }
+ *out=0;
+}
+
+/* SHOUTcast 1 title updates */
+int SHOUTCAST_OUTPUT::Output_Title_SendUpdate(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ char utf8title[1024] = {0};
+ char fixedtitle[3072] = {0}; // if every character is URL-encoded, we would get a maximum of 3 times the space needed
+ char buffer[2048] = {0};
+
+ WideCharToMultiByte(CP_ACP, 0, userData->Info.Title, -1, utf8title, sizeof(utf8title), 0, 0);
+ FixString(utf8title, fixedtitle);
+ fixedtitle[1023] = 0; // DNAS doesn't like titles bigger than 1k
+
+ // send the correct password based on dj name, etc
+ std::string t, u, p;
+ u = userData->Config->UserID;
+ p = userData->Config->Password;
+ if (!u.empty()) t = u + ":" + p;
+ else t = p;
+
+ snprintf(buffer, sizeof(buffer), "GET /admin.cgi?pass=%s&mode=updinfo&song=%s&dj=%s HTTP/1.0\n", (char *)t.data(), fixedtitle, userData->Config->UserID);
+ userData->Output->SendString(buffer);
+
+ stringstream s;
+ s << "User-Agent: SHOUTcast Source DSP v" << sourceVersion << " Title Update (Mozilla)\n\n";
+ userData->Output->SendString((char*)s.str().data());
+
+ userData->SlowClose = 1;
+ userData->Info.meta_cached = 1;
+ }UNLOCK
+ return OUT_DISCONNECT;
+}
+
+/* SHOUTcast 2 in-stream metada */
+int SHOUTCAST_OUTPUT::Output_Send_Metadata(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ if (userData->TitleCallback) {
+ if (userData->Connection >= 0 && userData->Connection < 5) {
+ userData->TitleCallback(userData->Connection, 0);
+ }
+ }
+ }UNLOCK
+ return OUT_SENDCONTENT;
+}
+
+/* SHOUTcast 2 in-stream metada */
+int SHOUTCAST_OUTPUT::Output_Send_Artwork(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ int artType = (userData->Info.meta_cached & 4 ? 1 : (userData->Info.meta_cached & 2 ? 0 : -1));
+ if (userData->TitleCallback) {
+ if (userData->Connection >= 0 && userData->Connection < 5) {
+ if (artType != -1) {
+ userData->TitleCallback(userData->Connection, 1);
+ // decrement counts to move to next part of image packets if needed
+ if (userData->Info.meta_cached & (artType ? 4 : 2)) {
+ userData->Info.art_cached[artType]--;
+ if (userData->Info.art_cached[artType] < 0) userData->Info.art_cached[artType] = 0;
+ }
+ }
+ }
+ } else {
+ if (artType != -1) {
+ userData->Info.art_cached[artType] = 0;
+ }
+ }
+ }UNLOCK
+ return OUT_SENDCONTENT;
+}
+
+int SHOUTCAST_OUTPUT::Output_Request_Cipher(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ if (LOBYTE(userData->Config->protocol) != 1) {
+ userData->Output->FlushSend();
+ createUvoxFrame(3, "2.1\0", MSG_CIPHER, userData);
+ UNLOCK
+ return OUT_RECV_CIPHER;
+ } else {
+ // shoutcast 1
+ UNLOCK
+ return OUT_SENDAUTH;
+ }
+ }UNLOCK
+ return state;
+}
+
+int SHOUTCAST_OUTPUT::Output_Receive_Cipher(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ if (userData->Output->GetReceiveBytesAvailable() > 0) {
+ memset(buf, '\0', sizeof(buf));
+ userData->Output->ReceiveLine(buf, sizeof(buf));
+ parseUvoxFrame(buf, out);
+ if (checkUvoxFrameForError(out, state, userData) == -1) {
+ UNLOCK
+ return OUT_DISCONNECT;
+ } else {
+ // copy the cipher key now we have it.
+ strcpy_s(userData->Config->cipherkey, sizeof(userData->Config->cipherkey)-1, out+4);
+ UNLOCK
+ userData->Config->protocol_retry = 0;
+ return OUT_SENDAUTH;
+ }
+ }
+
+ userData->Config->protocol_retry = MAKEWORD(LOBYTE(userData->Config->protocol_retry)+1, HIBYTE(userData->Config->protocol_retry));
+
+ // this handles automatic mode being enabled
+ if (!HIBYTE(userData->Config->protocol) &&
+ (LOBYTE(userData->Config->protocol_retry) > 5)) {
+ userData->Output->Close(!userData->SlowClose);
+ UNLOCK
+ return OUT_SENDAUTH;
+ }
+
+ }UNLOCK
+
+ return (LOBYTE(userData->Config->protocol_retry) > 5 ? OUT_DISCONNECT : state);
+}
+
+int SHOUTCAST_OUTPUT::Output_SendAuth(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ userData->Output->FlushSend();
+ userData->Info.Succeeded = 1;
+ std::string s,
+ u = userData->Config->UserID,
+ p = userData->Config->Password;
+
+ if (LOBYTE(userData->Config->protocol) != 1) {
+ uvAuth21 * auth = new uvAuth21();
+ std::string k;
+ k = userData->Config->cipherkey;
+ s = "2.1:";
+ s += (!userData->Config->StationID[0] ? "1" : userData->Config->StationID);
+ s += ":";
+ s += auth->encrypt(u, p, k);
+ createUvoxFrame(s.length(), (char *)s.data(), MSG_AUTH, userData);
+ delete auth;
+ } else {
+ if (!u.empty()) s = u + ":" + p;
+ else s = p;
+ userData->Output->SendString((char *)s.data());
+ userData->Output->SendString("\n");
+ }
+ UNLOCK
+ return OUT_RECVAUTHRESPONSE;
+ }UNLOCK
+ return state;
+}
+
+int SHOUTCAST_OUTPUT::Output_RecvAuthResponse(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ if (LOBYTE(userData->Config->protocol) != 1) {
+ if (userData->Output->GetReceiveBytesAvailable() > 0) {
+ memset(buf, '\0', sizeof(buf));
+ userData->Info.Succeeded = 1;
+ userData->Output->recv_bytes(buf, sizeof(buf));
+ parseUvoxFrame(buf, out);
+ int err = checkUvoxFrameForError(out, state, userData);
+ if (err == -1) {
+ UNLOCK
+ return OUT_DISCONNECT;
+ } else {
+ // test for a cipher failure
+ if (strncmp(buf, "ACK:", 4) == 0) {
+ userData->Info.Succeeded = -1;
+ userData->Info.ErrorMsg = "CipherFail";
+ UNLOCK
+ return OUT_FAIL_CIPHER;
+ }
+ UNLOCK
+ return OUT_SEND_MIME;
+ }
+ }
+ } else {
+ // auth shoutcast 1
+ if (userData->Output->GetReceiveBytesAvailable() > 0) {
+ userData->Output->ReceiveLine(buf, sizeof(buf));
+ char *ok = strstr(buf, "OK");
+ if (ok) { // we got OK response... shoutcast v1
+ userData->Info.Succeeded = 1;
+ UNLOCK
+ return OUT_SENDYP; // send the sc v1 YP stuff, now
+ } else {
+ userData->Info.Succeeded = 0;
+ if (strcmpi(buf, "invalid password") == 0) {
+ userData->Info.Succeeded = -1;
+ userData->Info.ErrorMsg = "NAK:Deny";
+ } else if (strcmpi(buf, "stream moved") == 0) {
+ userData->Info.Succeeded = -1;
+ userData->Info.ErrorMsg = "StreamMoved";
+ }
+ UNLOCK
+ return OUT_DISCONNECT;
+ }
+ }
+ }
+ }UNLOCK
+ return state;
+}
+
+int SHOUTCAST_OUTPUT::Output_Send_Mime(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ std::string s = userData->ContentType;
+ userData->Output->FlushSend();
+ createUvoxFrame(s.length(), (char *)s.data(), MSG_MIME_TYPE, userData);
+ }UNLOCK
+ return OUT_RECV_MIME;
+}
+
+int SHOUTCAST_OUTPUT::Output_Recv_Mime(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ if (userData->Output->GetReceiveBytesAvailable() > 0) {
+ memset(buf, '\0', sizeof(buf));
+ userData->Output->recv_bytes(buf, sizeof(buf));
+ parseUvoxFrame(buf, out);
+ UNLOCK
+ return OUT_SEND_BITRATE;
+ }
+ }UNLOCK
+ return state;
+}
+
+int SHOUTCAST_OUTPUT::Output_Send_Bitrate(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ char bitrate[128] = {0};
+ std::string s;
+ snprintf(bitrate, sizeof(bitrate), "%d:%d", userData->Bitrate*1000, userData->Bitrate*1000);
+ s = bitrate;
+ userData->Output->FlushSend();
+ createUvoxFrame(s.length(), (char *)s.data(), MSG_BROADCAST_SETUP, userData);
+ }UNLOCK
+ return OUT_RECV_BITRATE;
+}
+
+int SHOUTCAST_OUTPUT::Output_Recv_Bitrate(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ if (userData->Output->GetReceiveBytesAvailable() > 0) {
+ memset(buf, '\0', sizeof(buf));
+ userData->Output->recv_bytes(buf, sizeof(buf));
+ parseUvoxFrame(buf, out);
+ int err = checkUvoxFrameForError(out, state, userData);
+ if (err == -1) {
+ UNLOCK
+ return OUT_DISCONNECT;
+ } else {
+ UNLOCK
+ return OUT_SEND_BUFSIZE;
+ }
+ }
+ }UNLOCK
+ return state;
+}
+
+int SHOUTCAST_OUTPUT::Output_Send_Buf_Size(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ char bsize[32] = {0};
+ int toSend = (userData->Bitrate * 20)/8;
+ snprintf(bsize, sizeof(bsize), "%d:0", toSend);
+ std::string s = bsize;
+ userData->Output->FlushSend();
+ createUvoxFrame(s.length(), (char *)s.data(), MSG_NEGOTIATE_BUFFER_SIZE, userData);
+ }UNLOCK
+ return OUT_RECV_BUFSIZE;
+}
+
+int SHOUTCAST_OUTPUT::Output_Recv_Buf_Size(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ if (userData->Output->GetReceiveBytesAvailable() > 0) {
+ memset(buf, '\0', sizeof(buf));
+ userData->Output->recv_bytes(buf, sizeof(buf));
+ UNLOCK
+ return OUT_SEND_MAX;
+ }
+ }UNLOCK
+ return state;
+}
+
+int SHOUTCAST_OUTPUT::Output_Send_Max_Size(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ userData->Output->FlushSend();
+ createUvoxFrame(7, "16377:0\0", MSG_MAX_PAYLOAD_SIZE, userData);
+ }UNLOCK
+ return OUT_RECV_MAX;
+}
+
+int SHOUTCAST_OUTPUT::Output_Recv_Max_Size(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ if (userData->Output->GetReceiveBytesAvailable() > 0) {
+ memset(buf, '\0', sizeof(buf));
+ userData->Output->recv_bytes(buf, sizeof(buf));
+ parseUvoxFrame(buf, out);
+ UNLOCK
+ return OUT_SENDYP;
+ }
+ }UNLOCK
+ return state;
+}
+
+int SHOUTCAST_OUTPUT::Output_DUMMY(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ if (userData->Output->GetReceiveBytesAvailable() > 0) {
+ memset(buf, '\0', sizeof(buf));
+ userData->Output->recv_bytes(buf, sizeof(buf));
+ parseUvoxFrame(buf, out);
+ }
+ }UNLOCK
+ return state;
+}
+
+int SHOUTCAST_OUTPUT::Output_SendYP(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ if (LOBYTE(userData->Config->protocol) != 1) {
+ //icyname
+ std::string s;
+ s = userData->Config->Description;
+ createUvoxFrame(s.length(), (char *)s.data(), MSG_ICYNAME, userData);
+ Output_DUMMY(state, last_state, userData);
+
+ //icygenre
+ s = userData->Config->Genre;
+ createUvoxFrame(s.length(), (char *)s.data(), MSG_ICYGENRE, userData);
+ Output_DUMMY(state, last_state, userData);
+
+ //icyurl
+ s = userData->Config->ServerURL;
+ createUvoxFrame(s.length(), (char *)s.data(), MSG_ICYURL, userData);
+ Output_DUMMY(state, last_state, userData);
+
+ //icypub
+ char pub[2] = {0};
+ snprintf(pub, sizeof(pub), "%d", !!userData->Config->Public);
+ createUvoxFrame(1, pub, MSG_ICYPUB, userData);
+ Output_DUMMY(state, last_state, userData);
+ UNLOCK
+ return OUT_SEND_INITFLUSH;
+ } else {
+ char ypbuf[4096] = {0};
+ char ypbuf2[4096] = {0};
+ // send Description
+ snprintf(ypbuf, sizeof(ypbuf), "icy-name:%s\n", userData->Config->Description);
+ userData->Output->SendString(ypbuf);
+ // send Genre
+ ypbuf2[0] = 0;
+ if (strlen(userData->Config->Genre) > 0) {
+ snprintf((char *)&ypbuf2+strlen(ypbuf2), sizeof(ypbuf2), "%s", userData->Config->Genre);
+ }
+ snprintf(ypbuf, sizeof(ypbuf), "icy-genre:%s\n", ypbuf2);
+ userData->Output->SendString(ypbuf);
+ // send URL
+ snprintf(ypbuf, sizeof(ypbuf), "icy-url:%s\n", userData->Config->ServerURL);
+ userData->Output->SendString(ypbuf);
+ // send IRC
+ snprintf(ypbuf, sizeof(ypbuf), "icy-irc:%s\n", userData->Config->IRC);
+ userData->Output->SendString(ypbuf);
+ // send ICQ
+ snprintf(ypbuf, sizeof(ypbuf), "icy-icq:%s\n", userData->Config->ICQ);
+ userData->Output->SendString(ypbuf);
+ // send AIM
+ snprintf(ypbuf, sizeof(ypbuf), "icy-aim:%s\n", userData->Config->AIM);
+ userData->Output->SendString(ypbuf);
+ // send publicity
+ snprintf(ypbuf, sizeof(ypbuf), "icy-pub:%u\n", userData->Config->Public ? 1 : 0);
+ userData->Output->SendString(ypbuf);
+ // send bitrate (this is a huge bad big ugly hack... needs to be fixed, but this works so far)
+ snprintf(ypbuf, sizeof(ypbuf), "icy-br:%d\n", userData->Bitrate);
+ userData->Output->SendString(ypbuf);
+ // send content type (shouldn't be here as with the bitrate, but it works)
+ snprintf(ypbuf, sizeof(ypbuf), "content-type:%s\n", userData->ContentType);
+ userData->Output->SendString(ypbuf);
+ // end our list of configurations
+ userData->Output->SendString("\n");
+ UNLOCK
+ return OUT_SENDCONTENT;
+ }
+ }UNLOCK
+ return state;
+}
+
+int SHOUTCAST_OUTPUT::Output_Send_InitFlush(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ userData->Output->FlushSend();
+ createUvoxFrame(1, "0\0", MSG_FLUSH_CACHED_METADATA, userData);
+ }UNLOCK
+ return OUT_RECV_INITFLUSH;
+}
+
+int SHOUTCAST_OUTPUT::Output_Recv_InitFlush(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ Output_DUMMY(state, last_state, userData);
+ }UNLOCK
+ return OUT_SEND_INITSTANDBY;
+}
+
+int SHOUTCAST_OUTPUT::Output_Send_InitStandby(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ userData->Output->FlushSend();
+ createUvoxFrame(1, "0\0", MSG_STANDBY, userData);
+ }UNLOCK
+ return OUT_RECV_INITSTANDBY;//OUT_SENDCONTENT;
+}
+
+int SHOUTCAST_OUTPUT::Output_Recv_InitStandby(int state, int last_state, T_OUTPUT *userData) {
+ DEBUG_STATE
+ STATE;
+ LOCK{
+ if (userData->Output->GetReceiveBytesAvailable() > 0) {
+ memset(buf, '\0', sizeof(buf));
+ userData->Output->ReceiveLine(buf, sizeof(buf));
+ parseUvoxFrame(buf, out);
+ if (checkUvoxFrameForError(out, state, userData) == -1) {
+ UNLOCK
+ return OUT_DISCONNECT;
+ } else {
+ UNLOCK
+ return OUT_SENDCONTENT;//OUT_SEND_INTRO;
+ }
+ }
+ }UNLOCK
+ return OUT_SENDCONTENT;//OUT_SEND_INTRO;
+}
+
+/*int SHOUTCAST_OUTPUT::Output_Send_Intro(int state, T_OUTPUT *userData) {
+ LOCK{
+ }UNLOCK
+ return OUT_RECV_INTRO;
+}
+
+int SHOUTCAST_OUTPUT::Output_Recv_Intro(int state, T_OUTPUT *userData) {
+ LOCK{
+ }UNLOCK
+ return OUT_SEND_BACKUP;
+}
+
+int SHOUTCAST_OUTPUT::Output_Send_Backup(int state, T_OUTPUT *userData) {
+ LOCK{
+ }UNLOCK
+ return OUT_RECV_BACKUP;
+}
+
+int SHOUTCAST_OUTPUT::Output_Recv_Backup(int state, T_OUTPUT *userData) {
+ LOCK{
+ }UNLOCK
+ return OUT_SENDCONTENT;
+}*/ \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/uvAuth21/uvAuth21.cpp b/Src/Plugins/DSP/dsp_sc/sc2srclib/uvAuth21/uvAuth21.cpp
new file mode 100644
index 00000000..763507e9
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/uvAuth21/uvAuth21.cpp
@@ -0,0 +1,90 @@
+#include "uvAuth21.h"
+
+uvAuth21::uvAuth21(void) {
+}
+
+uvAuth21::~uvAuth21(void) {
+}
+
+string uvAuth21::encrypt(string user,string pass,string key) {
+ string blob;
+ uint8_t* username = (uint8_t*)user.data();
+ uint8_t* password = (uint8_t*)pass.data();
+ uint8_t* cipherkey = (uint8_t*)key.data();
+ blob = XTEA_encipher(username,user.length(),cipherkey,key.length());
+ blob += ':';
+ blob += XTEA_encipher(password,pass.length(),cipherkey,key.length());
+ return blob;
+}
+
+const char * uvAuth21::encrypt(char * user,char * pass,char * key) {
+ static string blob;
+ uint8_t* username = (uint8_t*)user;
+ uint8_t* password = (uint8_t*)pass;
+ uint8_t* cipherkey = (uint8_t*)key;
+ blob = XTEA_encipher(username,sizeof(user),cipherkey,sizeof(key));
+ blob += ':';
+ blob += XTEA_encipher(password,sizeof(pass),cipherkey,sizeof(key));
+ return blob.c_str();
+}
+
+// from wikipedia. Slightly modified to be 32/64 bit clean
+void uvAuth21::XTEA_encipher(__uint32* v, __uint32* k) {
+ unsigned int num_rounds = 32;
+ __uint32 v0=v[0], v1=v[1], i;
+ __uint32 sum=0, delta=0x9E3779B9;
+ for(i=0; i<num_rounds; i++) {
+ v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
+ sum += delta;
+ v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]);
+ }
+ v[0]=v0; v[1]=v1;
+}
+
+__uint32 uvAuth21::fourCharsToLong(__uint8 *s) {
+ __uint32 l = 0;
+ l |= s[0]; l <<= 8;
+ l |= s[1]; l <<= 8;
+ l |= s[2]; l <<= 8;
+ l |= s[3];
+ return l;
+}
+
+ std::vector<std::string> &uvAuth21::split(const std::string &s, char delim, std::vector<std::string> &elems) {
+ std::stringstream ss(s);
+ std::string item;
+ while(std::getline(ss, item, delim)) {
+ elems.push_back(item);
+ }
+ return elems;
+}
+
+std::vector<std::string> uvAuth21::dosplit(const std::string &s, char delim) {
+ std::vector<std::string> elems;
+ return split(s, delim, elems);
+}
+
+std::string uvAuth21::XTEA_encipher(const __uint8* c_data,size_t c_data_cnt, const __uint8* c_key,size_t c_key_cnt) {
+ std::ostringstream oss;
+ std::vector<__uint8> key(c_key,c_key + c_key_cnt);
+ std::vector<__uint8> data(c_data,c_data + c_data_cnt);
+
+ // key is always 128 bits
+ while(key.size() < 16) key.push_back(XTEA_KEY_PAD); // pad key with zero
+ __uint32 k[4] = { fourCharsToLong(&key[0]),fourCharsToLong(&key[4]),fourCharsToLong(&key[8]),fourCharsToLong(&key[12])};
+
+ // data is multiple of 64 bits
+ size_t siz = data.size();
+ while(siz % 8) { siz+=1; data.push_back(XTEA_DATA_PAD);} // pad data with zero
+
+ for(size_t x = 0; x < siz; x+=8) {
+ __uint32 v[2];
+ v[0] = fourCharsToLong(&data[x]);
+ v[1] = fourCharsToLong(&data[x+4]);
+ XTEA_encipher(v,k);
+ oss << setw(8) << setfill('0') << hex << v[0];
+ oss << setw(8) << setfill('0') << hex << v[1]; // hex values. uvox uses colon as seperator so we can't use chars for
+ // fear of collision
+ }
+ return oss.str();
+} \ No newline at end of file
diff --git a/Src/Plugins/DSP/dsp_sc/sc2srclib/uvAuth21/uvAuth21.h b/Src/Plugins/DSP/dsp_sc/sc2srclib/uvAuth21/uvAuth21.h
new file mode 100644
index 00000000..971ce02a
--- /dev/null
+++ b/Src/Plugins/DSP/dsp_sc/sc2srclib/uvAuth21/uvAuth21.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <stdio.h>
+#include "../replicant\foundation\win-x86\types.h"
+#include <string>
+#include <string.h>
+#include <iostream>
+#include <sstream>
+#include <vector>
+#include <iomanip>
+#include <assert.h>
+
+#define XTEA_KEY_PAD 0
+#define XTEA_DATA_PAD 0
+#define __uint32 uint32_t
+#define __uint8 uint8_t
+
+using namespace std;
+
+class uvAuth21 {
+public:
+ uvAuth21(void);
+ string encrypt(string user, string password, string key);
+ const char * encrypt(char * user,char * password,char * key);
+ ~uvAuth21(void);
+private:
+
+protected:
+ static void XTEA_encipher(__uint32* v, __uint32* k);
+ static __uint32 fourCharsToLong(__uint8 *s);
+ static string XTEA_encipher(const __uint8* c_data, size_t c_data_cnt, const __uint8* c_key, size_t c_key_cnt);
+ static std::vector<std::string> dosplit(const std::string &s, char delim);
+ static std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems);
+}; \ No newline at end of file