diff --git a/.gitignore b/.gitignore index 945fb3e..c9c559f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ *.o *.dylib *.so +echoprint-codegen +src/libcodegen.so.4.1.1 + +Debug +*.opendb +*~ \ No newline at end of file diff --git a/src/AudioBufferInput.h b/src/AudioBufferInput.h index c60dfdb..f7f3ca9 100644 --- a/src/AudioBufferInput.h +++ b/src/AudioBufferInput.h @@ -3,27 +3,26 @@ // Copyright 2011 The Echo Nest Corporation. All rights reserved. // - +#ifndef AUDIOBUFFERINPUT_H +#define AUDIOBUFFERINPUT_H #include "Common.h" #include #include -#ifndef AUDIOBUFFERINPUT_H -#define AUDIOBUFFERINPUT_H -#include "Params.h" #include "AudioStreamInput.h" class AudioBufferInput : public AudioStreamInput { -public: - AudioBufferInput(); - std::string GetName() {return "direct buffer";} - void SaveBuffer(const char*filename); - void SetBuffer(const float* pBuffer, uint numSamples); -protected: - std::string GetCommandLine(const char*){return "";} -private: + public: + AudioBufferInput(); + std::string GetName() {return "direct buffer";} + void SaveBuffer(const char*filename); + void SetBuffer(const float* pBuffer, uint numSamples); + protected: + std::string GetCommandLine(const char*) + {return "";} }; + #endif diff --git a/src/AudioStreamInput.cxx b/src/AudioStreamInput.cxx index 9033b07..a812e29 100644 --- a/src/AudioStreamInput.cxx +++ b/src/AudioStreamInput.cxx @@ -27,106 +27,107 @@ using std::string; namespace FFMPEG { - // Do we think FFmpeg will read this as an audio file? - bool IsAudioFile(const char* pFileName) { - static const char* supportedExtensions[] = {".mp3", ".m4a", ".mp4", ".aif", ".aiff", ".flac", ".au", ".wav", ".aac", ".flv"}; - // Not an exhaustive list. ogg and rm could be added if tested. - for (uint i = 0; i < NELEM(supportedExtensions); i++) { - if (File::ends_with(pFileName, supportedExtensions[i])) - return true; - } - return false; + // Do we think FFmpeg will read this as an audio file? + bool IsAudioFile(const char* pFileName) { + static const char* supportedExtensions[] = {".mp3", ".m4a", ".mp4", ".aif", ".aiff", ".flac", ".au", ".wav", ".aac", ".flv"}; + // Not an exhaustive list. ogg and rm could be added if tested. + for (uint i = 0; i < NELEM(supportedExtensions); i++) { + if (File::ends_with(pFileName, supportedExtensions[i])) + return true; } + return false; + } } bool AudioStreamInput::IsSupported(const char *path) { - return true; // Take a crack at anything, by default. The worst thing that will happen is that we fail. + return true; // Take a crack at anything, by default. The worst thing that will happen is that we fail. } -AudioStreamInput::AudioStreamInput() : _pSamples(NULL), _NumberSamples(0), _Offset_s(0), _Seconds(0) {} +AudioStreamInput::AudioStreamInput() : _pSamples(nullptr), _NumberSamples(0), _Offset_s(0), _Seconds(0) {} AudioStreamInput::~AudioStreamInput() { - if (_pSamples != NULL) - delete [] _pSamples, _pSamples = NULL; + delete [] _pSamples; + _pSamples = nullptr; } bool AudioStreamInput::ProcessFile(const char* filename, int offset_s/*=0*/, int seconds/*=0*/) { - if (!File::Exists(filename) || !IsSupported(filename)) - return false; + if (!File::Exists(filename) || !IsSupported(filename)) + return false; - _Offset_s = offset_s; - _Seconds = seconds; - std::string message = GetCommandLine(filename); + _Offset_s = offset_s; + _Seconds = seconds; + std::string message = GetCommandLine(filename); - FILE* fp = popen(message.c_str(), POPEN_MODE); - bool ok = (fp != NULL); - if (ok) + FILE* fp = popen(message.c_str(), POPEN_MODE); + bool ok = (fp != nullptr); + if (ok) { - bool did_work = ProcessFilePointer(fp); - bool succeeded = !pclose(fp); - ok = did_work && succeeded; + bool did_work = ProcessFilePointer(fp); + bool succeeded = !pclose(fp); + ok = did_work && succeeded; } - else - fprintf(stderr, "AudioStreamInput::ProcessFile can't open %s\n", filename); + else + fprintf(stderr, "AudioStreamInput::ProcessFile can't open %s\n", filename); - return ok; + return ok; } // reads raw signed 16-bit shorts from a file bool AudioStreamInput::ProcessRawFile(const char* rawFilename) { - FILE* fp = fopen(rawFilename, "r"); // TODO: Windows - bool ok = (fp != NULL); - if (ok) + FILE* fp = fopen(rawFilename, "r"); // TODO: Windows + bool ok = (fp != nullptr); + if (ok) { - ok = ProcessFilePointer(fp); - fclose(fp); + ok = ProcessFilePointer(fp); + fclose(fp); } - return ok; + return ok; } // reads raw signed 16-bit shorts from stdin, for example: // ffmpeg -i fille.mp3 -f s16le -ac 1 -ar 11025 - | TestAudioSTreamInput bool AudioStreamInput::ProcessStandardInput(void) { - // TODO - Windows will explodey at not setting O_BINARY on stdin. - return ProcessFilePointer(stdin); + // TODO - Windows will explodey at not setting O_BINARY on stdin. + return ProcessFilePointer(stdin); } bool AudioStreamInput::ProcessFilePointer(FILE* pFile) { - std::vector vChunks; - uint nSamplesPerChunk = (uint) Params::AudioStreamInput::SamplingRate * Params::AudioStreamInput::SecondsPerChunk; - uint samplesRead = 0; - do { - short* pChunk = new short[nSamplesPerChunk]; - samplesRead = fread(pChunk, sizeof (short), nSamplesPerChunk, pFile); - _NumberSamples += samplesRead; - vChunks.push_back(pChunk); - } while (samplesRead > 0); - - // Convert from shorts to 16-bit floats and copy into sample buffer. - uint sampleCounter = 0; - _pSamples = new float[_NumberSamples]; - uint samplesLeft = _NumberSamples; - for (uint i = 0; i < vChunks.size(); i++) + std::vector vChunks; + + uint nSamplesPerChunk = static_cast(Params::AudioStreamInput::SamplingRate * Params::AudioStreamInput::SecondsPerChunk); + uint samplesRead = 0; + do { + short* pChunk = new short[nSamplesPerChunk]; + samplesRead = fread(pChunk, sizeof (short), nSamplesPerChunk, pFile); + _NumberSamples += samplesRead; + vChunks.push_back(pChunk); + } while (samplesRead > 0); + + // Convert from shorts to 16-bit floats and copy into sample buffer. + uint sampleCounter = 0; + _pSamples = new float[_NumberSamples]; + uint samplesLeft = _NumberSamples; + for (uint i = 0; i < vChunks.size(); i++) { - short* pChunk = vChunks[i]; - uint numSamples = samplesLeft < nSamplesPerChunk ? samplesLeft : nSamplesPerChunk; + short* pChunk = vChunks[i]; + uint numSamples = samplesLeft < nSamplesPerChunk ? samplesLeft : nSamplesPerChunk; - for (uint j = 0; j < numSamples; j++) - _pSamples[sampleCounter++] = (float) pChunk[j] / 32768.0f; + for (uint j = 0; j < numSamples; j++) + _pSamples[sampleCounter++] = (float) pChunk[j] / 32768.0f; - samplesLeft -= numSamples; - delete [] pChunk, vChunks[i] = NULL; + samplesLeft -= numSamples; + delete [] pChunk, vChunks[i] = nullptr; } - assert(samplesLeft == 0); + assert(samplesLeft == 0); - int error = ferror(pFile); - bool success = error == 0; + int error = ferror(pFile); + bool success = error == 0; - if (!success) - perror("ProcessFilePointer error"); - return success; + if (!success) + perror("ProcessFilePointer error"); + return success; } diff --git a/src/AudioStreamInput.h b/src/AudioStreamInput.h index 47b9227..12e56bf 100644 --- a/src/AudioStreamInput.h +++ b/src/AudioStreamInput.h @@ -13,7 +13,7 @@ #include #include "File.h" #if defined(_WIN32) && !defined(__MINGW32__) -#define snprintf _snprintf +#define snprintf _snprintf_s #define DEVNULL "nul" #else #define DEVNULL "/dev/null" diff --git a/src/Codegen.cxx b/src/Codegen.cxx index b391b38..cedeebe 100644 --- a/src/Codegen.cxx +++ b/src/Codegen.cxx @@ -26,25 +26,20 @@ Codegen::Codegen(const float* pcm, unsigned int numSamples, int start_offset) { if (Params::AudioStreamInput::MaxSamples < (uint)numSamples) throw std::runtime_error("File was too big\n"); - Whitening *pWhitening = new Whitening(pcm, numSamples); + std::unique_ptr pWhitening (new Whitening(pcm, numSamples)); pWhitening->Compute(); - AudioBufferInput *pAudio = new AudioBufferInput(); + std::unique_ptr pAudio (new AudioBufferInput()); pAudio->SetBuffer(pWhitening->getWhitenedSamples(), pWhitening->getNumSamples()); - SubbandAnalysis *pSubbandAnalysis = new SubbandAnalysis(pAudio); + std::unique_ptr pSubbandAnalysis (new SubbandAnalysis(pAudio->getSamples(), pAudio->getNumSamples())); pSubbandAnalysis->Compute(); - Fingerprint *pFingerprint = new Fingerprint(pSubbandAnalysis, start_offset); + std::unique_ptr pFingerprint (new Fingerprint(std::move(pSubbandAnalysis), start_offset)); pFingerprint->Compute(); _CodeString = createCodeString(pFingerprint->getCodes()); _NumCodes = pFingerprint->getCodes().size(); - - delete pFingerprint; - delete pSubbandAnalysis; - delete pWhitening; - delete pAudio; } string Codegen::createCodeString(vector vCodes) { diff --git a/src/Common.h b/src/Common.h index ccce7d0..be35529 100644 --- a/src/Common.h +++ b/src/Common.h @@ -7,8 +7,6 @@ #ifndef COMMON_H #define COMMON_H - - #include #ifndef _WIN32 #include @@ -28,17 +26,11 @@ #include #include - -#ifndef NULL -#define NULL 0 -#endif - - // Returns the current date in seconds. The precision is in microseconds. static inline double now (void) { struct timeval tv; double now; - gettimeofday (&tv, NULL); + gettimeofday (&tv, nullptr); now = 1e-6 * tv.tv_usec + tv.tv_sec; return now; } diff --git a/src/File.h b/src/File.h index 8d5b1cd..aab6521 100644 --- a/src/File.h +++ b/src/File.h @@ -26,8 +26,8 @@ bool WriteStuffToFile(const char* filename) class File { public: File(const char* filename){_f = fopen(filename, "w");}; - ~File(){fclose(_f); _f = NULL;} - operator bool(){return _f != NULL;} + ~File(){fclose(_f); _f = nullptr;} + operator bool(){return _f != nullptr;} operator FILE*(){return _f;} static bool Exists(const char* filename){return (access(filename, F_OK) == 0);} static bool ends_with(const char* filename, const char* ending) { diff --git a/src/Fingerprint.cxx b/src/Fingerprint.cxx index 7457170..7c19060 100644 --- a/src/Fingerprint.cxx +++ b/src/Fingerprint.cxx @@ -48,8 +48,9 @@ unsigned int MurmurHash2 ( const void * key, int len, unsigned int seed ) { return h; } -Fingerprint::Fingerprint(SubbandAnalysis* pSubbandAnalysis, int offset) - : _pSubbandAnalysis(pSubbandAnalysis), _Offset(offset) { } +Fingerprint::Fingerprint(std::unique_ptr pSubbandAnalysis, int offset) + : _pSubbandAnalysis(std::move(pSubbandAnalysis)), _Offset(offset) +{ } uint Fingerprint::adaptiveOnsets(int ttarg, matrix_u&out, uint*&onset_counter_for_band) { @@ -171,7 +172,7 @@ uint Fingerprint::adaptiveOnsets(int ttarg, matrix_u&out, uint*&onset_counter_fo // dan is going to beat me if i call this "decimated_time_for_frame" like i want to uint Fingerprint::quantized_time_for_frame_delta(uint frame_delta) { double time_for_frame_delta = (double)frame_delta / ((double)Params::AudioStreamInput::SamplingRate / 32.0); - return ((int)floor((time_for_frame_delta * 1000.0) / (float)QUANTIZE_DT_S) * QUANTIZE_DT_S) / floor(QUANTIZE_DT_S*1000.0); + return (static_cast(floor((time_for_frame_delta * 1000.0) / (float)QUANTIZE_DT_S) * QUANTIZE_DT_S) / floor(QUANTIZE_DT_S*1000.0)); } uint Fingerprint::quantized_time_for_frame_absolute(uint frame) { diff --git a/src/Fingerprint.h b/src/Fingerprint.h index cd4c784..c5c38ff 100644 --- a/src/Fingerprint.h +++ b/src/Fingerprint.h @@ -30,14 +30,14 @@ unsigned int MurmurHash2 ( const void * key, int len, unsigned int seed ); class Fingerprint { public: + Fingerprint(std::unique_ptr pSubbandAnalysis, int offset); uint quantized_time_for_frame_delta(uint frame_delta); uint quantized_time_for_frame_absolute(uint frame); - Fingerprint(SubbandAnalysis* pSubbandAnalysis, int offset); void Compute(); uint adaptiveOnsets(int ttarg, matrix_u&out, uint*&onset_counter_for_band) ; - std::vector& getCodes(){return _Codes;} + std::vector& getCodes() {return _Codes;} protected: - SubbandAnalysis *_pSubbandAnalysis; + std::unique_ptr _pSubbandAnalysis; int _Offset; std::vector _Codes; }; diff --git a/src/Makefile b/src/Makefile index f87e424..97b989e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -12,7 +12,7 @@ OPTFLAGS=-O3 -DBOOST_UBLAS_NDEBUG -DNDEBUG BOOST_CFLAGS=-I/usr/local/include/boost-1_35 TAGLIB_CFLAGS=`taglib-config --cflags` TAGLIB_LIBS=`taglib-config --libs` -CXXFLAGS=-Wall $(BOOST_CFLAGS) $(TAGLIB_CFLAGS) -fPIC $(OPTFLAGS) +CXXFLAGS=-std=c++11 -Wall $(BOOST_CFLAGS) $(TAGLIB_CFLAGS) -fPIC $(OPTFLAGS) CFLAGS=-Wall -fPIC $(OPTFLAGS) LDFLAGS=$(TAGLIB_LIBS) -lz -lpthread $(OPTFLAGS) LIBNAME=libcodegen.so diff --git a/src/MatrixUtility.cxx b/src/MatrixUtility.cxx index 4e27c0d..a962bdb 100644 --- a/src/MatrixUtility.cxx +++ b/src/MatrixUtility.cxx @@ -13,7 +13,7 @@ namespace MatrixUtility { bool TextFileOutput(const matrix_f& A, const char* filename) { FILE *matrix_file = fopen(filename, "w"); - bool success = (matrix_file != NULL); + bool success = (matrix_file != nullptr); if (success) { const float *d = &A.data()[0]; for (uint i = 0; i < A.size1(); i++) { @@ -29,7 +29,7 @@ bool TextFileOutput(const matrix_f& A, const char* filename) { bool FileOutput(const matrix_f& A, const char* filename) { FILE *matrix_file = fopen(filename, "wb"); - bool success = (matrix_file != NULL); + bool success = (matrix_file != nullptr); if (success) { uint mm = A.size1(); uint mn = A.size2(); diff --git a/src/Metadata.cxx b/src/Metadata.cxx index 3d0248e..823220e 100644 --- a/src/Metadata.cxx +++ b/src/Metadata.cxx @@ -14,16 +14,16 @@ Metadata::Metadata(const string& file) : _Filename(file), _Artist(""), _Album("" // TODO: Consider removing the path from the filename -- not sure if we can do this in a platform-independent way. TagLib::FileRef f(_Filename.c_str()); - TagLib::Tag* tag = f.isNull() ? NULL : f.tag(); - if (tag != NULL) { + TagLib::Tag* tag = f.isNull() ? nullptr : f.tag(); + if (tag) { _Artist = tag->artist().to8Bit(true); _Album = tag->album().to8Bit(true); _Title = tag->title().to8Bit(true); _Genre = tag->genre().to8Bit(true); } - TagLib::AudioProperties* properties = f.isNull() ? NULL : f.audioProperties(); - if (properties != NULL) { + TagLib::AudioProperties* properties = f.isNull() ? nullptr : f.audioProperties(); + if (properties) { _Bitrate = properties->bitrate(); _SampleRate = properties->sampleRate(); _Seconds = properties->length(); diff --git a/src/SubbandAnalysis.cxx b/src/SubbandAnalysis.cxx index 807f3bf..ff06a1c 100644 --- a/src/SubbandAnalysis.cxx +++ b/src/SubbandAnalysis.cxx @@ -11,12 +11,6 @@ #include "win_funcs.h" #endif -SubbandAnalysis::SubbandAnalysis(AudioStreamInput* pAudio) { - _pSamples = pAudio->getSamples(); - _NumSamples = pAudio->getNumSamples(); - Init(); -} - SubbandAnalysis::SubbandAnalysis(const float* pSamples, uint numSamples) : _pSamples(pSamples), _NumSamples(numSamples) { Init(); @@ -27,10 +21,10 @@ SubbandAnalysis::~SubbandAnalysis() { void SubbandAnalysis::Init() { // Calculate the analysis filter bank coefficients - _Mr = matrix_f(M_ROWS, M_COLS); - _Mi = matrix_f(M_ROWS, M_COLS); - for (uint i = 0; i < M_ROWS; ++i) { - for (uint k = 0; k < M_COLS; ++k) { + _Mr = matrix_f(SubbandFilterBank::M_ROWS, SubbandFilterBank::M_COLS); + _Mi = matrix_f(SubbandFilterBank::M_ROWS, SubbandFilterBank::M_COLS); + for (uint i = 0; i < SubbandFilterBank::M_ROWS; ++i) { + for (uint k = 0; k < SubbandFilterBank::M_COLS; ++k) { _Mr(i,k) = cos((2*i + 1)*(k-4)*(M_PI/16.0)); _Mi(i,k) = sin((2*i + 1)*(k-4)*(M_PI/16.0)); } @@ -40,30 +34,30 @@ void SubbandAnalysis::Init() { void SubbandAnalysis::Compute() { uint t, i, j; - float Z[C_LEN]; - float Y[M_COLS]; + float Z[SubbandFilterBank::C_LEN]; + float Y[SubbandFilterBank::M_COLS]; - _NumFrames = (_NumSamples - C_LEN + 1)/SUBBANDS; + _NumFrames = (_NumSamples - SubbandFilterBank::C_LEN + 1)/ SubbandFilterBank::SUBBANDS; assert(_NumFrames > 0); - _Data = matrix_f(SUBBANDS, _NumFrames); + _Data = matrix_f(SubbandFilterBank::SUBBANDS, _NumFrames); for (t = 0; t < _NumFrames; ++t) { - for (i = 0; i < C_LEN; ++i) { - Z[i] = _pSamples[ t*SUBBANDS + i] * SubbandFilterBank::C[i]; + for (i = 0; i < SubbandFilterBank::C_LEN; ++i) { + Z[i] = _pSamples[ t*SubbandFilterBank::SUBBANDS + i] * SubbandFilterBank::C[i]; } - for (i = 0; i < M_COLS; ++i) { + for (i = 0; i < SubbandFilterBank::M_COLS; ++i) { Y[i] = Z[i]; } - for (i = 0; i < M_COLS; ++i) { - for (j = 1; j < M_ROWS; ++j) { - Y[i] += Z[i + M_COLS*j]; + for (i = 0; i < SubbandFilterBank::M_COLS; ++i) { + for (j = 1; j < SubbandFilterBank::M_ROWS; ++j) { + Y[i] += Z[i + SubbandFilterBank::M_COLS*j]; } } - for (i = 0; i < M_ROWS; ++i) { + for (i = 0; i < SubbandFilterBank::M_ROWS; ++i) { float Dr = 0, Di = 0; - for (j = 0; j < M_COLS; ++j) { + for (j = 0; j < SubbandFilterBank::M_COLS; ++j) { Dr += _Mr(i,j) * Y[j]; Di -= _Mi(i,j) * Y[j]; } diff --git a/src/SubbandAnalysis.h b/src/SubbandAnalysis.h index 68f00bf..082d619 100644 --- a/src/SubbandAnalysis.h +++ b/src/SubbandAnalysis.h @@ -6,16 +6,18 @@ #ifndef SUBBANDANALYSIS_H #define SUBBANDANALYSIS_H + #include "Common.h" #include "Params.h" #include "MatrixUtility.h" -#define C_LEN 128 -#define SUBBANDS 8 -#define M_ROWS 8 -#define M_COLS 16 - namespace SubbandFilterBank { + static const unsigned int C_LEN = 128; + static const unsigned int SUBBANDS = 8; + + static const unsigned int M_ROWS = 8; + static const unsigned int M_COLS = 16; + // 128pt, 1/8th band low-pass prototype subsampled from Table_analysis_window static const float C[C_LEN] = { 0.000000477, 0.000000954, 0.000001431, 0.000002384, 0.000003815, 0.000006199, 0.000009060, 0.000013828, @@ -36,18 +38,15 @@ namespace SubbandFilterBank { -0.000009060, -0.000006199, -0.000003815, -0.000002384, -0.000001431, -0.000000954, -0.000000477, 0}; } -class AudioStreamInput; - class SubbandAnalysis { public: inline SubbandAnalysis() {}; - SubbandAnalysis(AudioStreamInput* pAudio); SubbandAnalysis(const float* pSamples, uint numSamples); virtual ~SubbandAnalysis(); void Compute(); public: inline uint getNumFrames() const {return _NumFrames;} - inline uint getNumBands() const {return SUBBANDS;} + inline uint getNumBands() const {return SubbandFilterBank::SUBBANDS;} const matrix_f& getMatrix() {return _Data;} protected: diff --git a/src/main.cxx b/src/main.cxx index 8b2b389..3f38cf4 100644 --- a/src/main.cxx +++ b/src/main.cxx @@ -8,8 +8,8 @@ #include #include #ifndef _WIN32 - #include - #include +#include +#include #endif #include #include @@ -20,30 +20,28 @@ #include #define MAX_FILES 200000 -using namespace std; - // The response from the codegen. Contains all the fields necessary // to create a json string. typedef struct { - char *error; - char *filename; - int start_offset; - int duration; - int tag; - double t1; - double t2; - int numSamples; - Codegen* codegen; + char *error; + char *filename; + int start_offset; + int duration; + int tag; + double t1; + double t2; + int numSamples; + Codegen* codegen; } codegen_response_t; // Struct to pass to the worker threads typedef struct { - char *filename; - int start_offset; - int duration; - int tag; - int done; - codegen_response_t *response; + char *filename; + int start_offset; + int duration; + int tag; + int done; + codegen_response_t *response; } thread_parm_t; // Thank you http://stackoverflow.com/questions/150355/programmatically-find-the-number-of-cores-on-a-machine @@ -58,290 +56,290 @@ typedef struct { int getNumCores() { #ifdef WIN32 - SYSTEM_INFO sysinfo; - GetSystemInfo(&sysinfo); - return sysinfo.dwNumberOfProcessors; + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + return sysinfo.dwNumberOfProcessors; #elif MACOS - int nm[2]; - size_t len = 4; - uint32_t count; - - nm[0] = CTL_HW; nm[1] = HW_AVAILCPU; - sysctl(nm, 2, &count, &len, NULL, 0); - - if(count < 1) { - nm[1] = HW_NCPU; - sysctl(nm, 2, &count, &len, NULL, 0); - if(count < 1) { count = 1; } - } - return count; + int nm[2]; + size_t len = 4; + uint32_t count; + + nm[0] = CTL_HW; nm[1] = HW_AVAILCPU; + sysctl(nm, 2, &count, &len, nullptr, 0); + + if(count < 1) { + nm[1] = HW_NCPU; + sysctl(nm, 2, &count, &len, nullptr, 0); + if(count < 1) { count = 1; } + } + return count; #else - return sysconf(_SC_NPROCESSORS_ONLN); + return sysconf(_SC_NPROCESSORS_ONLN); #endif } // deal with quotes etc in json std::string escape(const string& value) { - std::string s(value); - std::string out = ""; - out.reserve(s.size()); - for (size_t i = 0; i < s.size(); i++) { - char c = s[i]; - if ((unsigned char)c < 31) - continue; - - switch (c) { - case '"' : out += "\\\""; break; - case '\\': out += "\\\\"; break; - case '\b': out += "\\b" ; break; - case '\f': out += "\\f" ; break; - case '\n': out += "\\n" ; break; - case '\r': out += "\\r" ; break; - case '\t': out += "\\t" ; break; - // case '/' : out += "\\/" ; break; // Unnecessary? - default: - out += c; - // TODO: do something with unicode? - } + std::string s(value); + std::string out = ""; + out.reserve(s.size()); + for (size_t i = 0; i < s.size(); i++) { + char c = s[i]; + if ((unsigned char)c < 31) + continue; + + switch (c) { + case '"' : out += "\\\""; break; + case '\\': out += "\\\\"; break; + case '\b': out += "\\b" ; break; + case '\f': out += "\\f" ; break; + case '\n': out += "\\n" ; break; + case '\r': out += "\\r" ; break; + case '\t': out += "\\t" ; break; + // case '/' : out += "\\/" ; break; // Unnecessary? + default: + out += c; + // TODO: do something with unicode? } + } - return out; + return out; } codegen_response_t *codegen_file(char* filename, int start_offset, int duration, int tag) { - // Given a filename, perform a codegen on it and get the response - // This is called by a thread - double t1 = now(); - codegen_response_t *response = (codegen_response_t *)malloc(sizeof(codegen_response_t)); - response->error = NULL; - response->codegen = NULL; - - auto_ptr pAudio(new FfmpegStreamInput()); - pAudio->ProcessFile(filename, start_offset, duration); - - if (pAudio.get() == NULL) { // Unable to decode! - char* output = (char*) malloc(16384); - sprintf(output,"{\"error\":\"could not create decoder\", \"tag\":%d, \"metadata\":{\"filename\":\"%s\"}}", + // Given a filename, perform a codegen on it and get the response + // This is called by a thread + double t1 = now(); + codegen_response_t *response = (codegen_response_t *)malloc(sizeof(codegen_response_t)); + response->error = nullptr; + response->codegen = nullptr; + + std::auto_ptr pAudio(new FfmpegStreamInput()); + pAudio->ProcessFile(filename, start_offset, duration); + + if (pAudio.get() == nullptr) { // Unable to decode! + char* output = (char*) malloc(16384); + sprintf(output,"{\"error\":\"could not create decoder\", \"tag\":%d, \"metadata\":{\"filename\":\"%s\"}}", tag, escape(filename).c_str()); - response->error = output; - return response; - } + response->error = output; + return response; + } - int numSamples = pAudio->getNumSamples(); + int numSamples = pAudio->getNumSamples(); - if (numSamples < 1) { - char* output = (char*) malloc(16384); - sprintf(output,"{\"error\":\"could not decode\", \"tag\":%d, \"metadata\":{\"filename\":\"%s\"}}", + if (numSamples < 1) { + char* output = (char*) malloc(16384); + sprintf(output,"{\"error\":\"could not decode\", \"tag\":%d, \"metadata\":{\"filename\":\"%s\"}}", tag, escape(filename).c_str()); - response->error = output; - return response; - } - t1 = now() - t1; + response->error = output; + return response; + } + t1 = now() - t1; - double t2 = now(); - Codegen *pCodegen = new Codegen(pAudio->getSamples(), numSamples, start_offset); - t2 = now() - t2; + double t2 = now(); + Codegen *pCodegen = new Codegen(pAudio->getSamples(), numSamples, start_offset); + t2 = now() - t2; - response->t1 = t1; - response->t2 = t2; - response->numSamples = numSamples; - response->codegen = pCodegen; - response->start_offset = start_offset; - response->duration = duration; - response->tag = tag; - response->filename = filename; + response->t1 = t1; + response->t2 = t2; + response->numSamples = numSamples; + response->codegen = pCodegen; + response->start_offset = start_offset; + response->duration = duration; + response->tag = tag; + response->filename = filename; - return response; + return response; } void *threaded_codegen_file(void *parm) { - // pthread stub to invoke json_string_for_file - thread_parm_t *p = (thread_parm_t *)parm; - codegen_response_t *response = codegen_file(p->filename, p->start_offset, p->duration, p->tag); - p->response = response; - // mark when we're done so the controlling thread can move on. - p->done = 1; - return NULL; + // pthread stub to invoke json_string_for_file + thread_parm_t *p = (thread_parm_t *)parm; + codegen_response_t *response = codegen_file(p->filename, p->start_offset, p->duration, p->tag); + p->response = response; + // mark when we're done so the controlling thread can move on. + p->done = 1; + return nullptr; } void print_json_to_screen(char* output, int count, int done) { - // Print a json block depending on how many there are and where we are. - if(done==1 && count>1) { - printf("[\n%s,\n", output); - } else if(done==1 && count == 1) { - printf("[\n%s\n]\n", output); - } else if(done == count) { - printf("%s\n]\n", output); - } else { - printf("%s,\n", output); - } + // Print a json block depending on how many there are and where we are. + if(done==1 && count>1) { + printf("[\n%s,\n", output); + } else if(done==1 && count == 1) { + printf("[\n%s\n]\n", output); + } else if(done == count) { + printf("%s\n]\n", output); + } else { + printf("%s,\n", output); + } } char *make_json_string(codegen_response_t* response) { - if (response->error != NULL) { - return response->error; - } + if (response->error) { + return response->error; + } - // Get the ID3 tag information. - auto_ptr pMetadata(new Metadata(response->filename)); - - // preamble + codelen - char* output = (char*) malloc(sizeof(char)*(16384 + strlen(response->codegen->getCodeString().c_str()) )); - - sprintf(output,"{\"metadata\":{\"artist\":\"%s\", \"release\":\"%s\", \"title\":\"%s\", \"genre\":\"%s\", \"bitrate\":%d," - "\"sample_rate\":%d, \"duration\":%d, \"filename\":\"%s\", \"samples_decoded\":%d, \"given_duration\":%d," - " \"start_offset\":%d, \"version\":%2.2f, \"codegen_time\":%2.6f, \"decode_time\":%2.6f}, \"code_count\":%d," - " \"code\":\"%s\", \"tag\":%d}", - escape(pMetadata->Artist()).c_str(), - escape(pMetadata->Album()).c_str(), - escape(pMetadata->Title()).c_str(), - escape(pMetadata->Genre()).c_str(), - pMetadata->Bitrate(), - pMetadata->SampleRate(), - pMetadata->Seconds(), - escape(response->filename).c_str(), - response->numSamples, - response->duration, - response->start_offset, - response->codegen->getVersion(), - response->t2, - response->t1, - response->codegen->getNumCodes(), - response->codegen->getCodeString().c_str(), - response->tag - ); - return output; + // Get the ID3 tag information. + std::auto_ptr pMetadata(new Metadata(response->filename)); + + // preamble + codelen + char* output = (char*) malloc(sizeof(char)*(16384 + strlen(response->codegen->getCodeString().c_str()) )); + + sprintf(output,"{\"metadata\":{\"artist\":\"%s\", \"release\":\"%s\", \"title\":\"%s\", \"genre\":\"%s\", \"bitrate\":%d," + "\"sample_rate\":%d, \"duration\":%d, \"filename\":\"%s\", \"samples_decoded\":%d, \"given_duration\":%d," + " \"start_offset\":%d, \"version\":%2.2f, \"codegen_time\":%2.6f, \"decode_time\":%2.6f}, \"code_count\":%d," + " \"code\":\"%s\", \"tag\":%d}", + escape(pMetadata->Artist()).c_str(), + escape(pMetadata->Album()).c_str(), + escape(pMetadata->Title()).c_str(), + escape(pMetadata->Genre()).c_str(), + pMetadata->Bitrate(), + pMetadata->SampleRate(), + pMetadata->Seconds(), + escape(response->filename).c_str(), + response->numSamples, + response->duration, + response->start_offset, + response->codegen->getVersion(), + response->t2, + response->t1, + response->codegen->getNumCodes(), + response->codegen->getCodeString().c_str(), + response->tag + ); + return output; } int main(int argc, char** argv) { - if (argc < 2) { - fprintf(stderr, "Usage: %s [ filename | -s ] [seconds_start] [seconds_duration] [< file_list (if -s is set)]\n", argv[0]); - exit(-1); - } + if (argc < 2) { + fprintf(stderr, "Usage: %s [ filename | -s ] [seconds_start] [seconds_duration] [< file_list (if -s is set)]\n", argv[0]); + exit(-1); + } + + try { + string files[MAX_FILES]; + char *filename = argv[1]; + int count = 0; + int start_offset = 0; + int duration = 0; + int already = 0; + if (argc > 2) start_offset = atoi(argv[2]); + if (argc > 3) duration = atoi(argv[3]); + if (argc > 4) already = atoi(argv[4]); + // If you give it -s, it means to read in a list of files from stdin. + if (strcmp(filename, "-s") == 0) { + while(std::cin) { + if (count < MAX_FILES) { + string temp_str; + getline(std::cin, temp_str); + if (temp_str.size() > 2) + files[count++] = temp_str; + } else { + throw std::runtime_error("Too many files on stdin to process\n"); + } + } + } else files[count++] = filename; - try { - string files[MAX_FILES]; - char *filename = argv[1]; - int count = 0; - int start_offset = 0; - int duration = 0; - int already = 0; - if (argc > 2) start_offset = atoi(argv[2]); - if (argc > 3) duration = atoi(argv[3]); - if (argc > 4) already = atoi(argv[4]); - // If you give it -s, it means to read in a list of files from stdin. - if (strcmp(filename, "-s") == 0) { - while(cin) { - if (count < MAX_FILES) { - string temp_str; - getline(cin, temp_str); - if (temp_str.size() > 2) - files[count++] = temp_str; - } else { - throw std::runtime_error("Too many files on stdin to process\n"); - } - } - } else files[count++] = filename; - - if(count == 0) throw std::runtime_error("No files given.\n"); + if(count == 0) throw std::runtime_error("No files given.\n"); #ifdef _WIN32 - // Threading doesn't work in windows yet. - for(int i=0;icodegen) { - delete response->codegen; - } - free(response); - free(output); - } - return 0; + // Threading doesn't work in windows yet. + for(int i=0;icodegen) { + delete response->codegen; + } + free(response); + free(output); + } + return 0; #else - // Figure out how many threads to use based on # of cores - int num_threads = getNumCores(); - if (num_threads > 8) num_threads = 8; - if (num_threads < 2) num_threads = 2; - if (num_threads > count) num_threads = count; - - // Setup threading - pthread_t *t = (pthread_t*)malloc(sizeof(pthread_t)*num_threads); - thread_parm_t **parm = (thread_parm_t**)malloc(sizeof(thread_parm_t*)*num_threads); - pthread_attr_t *attr = (pthread_attr_t*)malloc(sizeof(pthread_attr_t)*num_threads); - - // Kick off the first N threads - int still_left = count-1-already; - for(int i=0;ifilename = (char*)files[still_left].c_str(); - parm[i]->start_offset = start_offset; + // Figure out how many threads to use based on # of cores + int num_threads = getNumCores(); + if (num_threads > 8) num_threads = 8; + if (num_threads < 2) num_threads = 2; + if (num_threads > count) num_threads = count; + + // Setup threading + pthread_t *t = (pthread_t*)malloc(sizeof(pthread_t)*num_threads); + thread_parm_t **parm = (thread_parm_t**)malloc(sizeof(thread_parm_t*)*num_threads); + pthread_attr_t *attr = (pthread_attr_t*)malloc(sizeof(pthread_attr_t)*num_threads); + + // Kick off the first N threads + int still_left = count-1-already; + for(int i=0;ifilename = (char*)files[still_left].c_str(); + parm[i]->start_offset = start_offset; + parm[i]->tag = still_left; + parm[i]->duration = duration; + parm[i]->done = 0; + still_left--; + pthread_attr_init(&attr[i]); + pthread_attr_setdetachstate(&attr[i], PTHREAD_CREATE_DETACHED); + // Kick off the thread + if (pthread_create(&t[i], &attr[i], threaded_codegen_file, (void*)parm[i])) + throw std::runtime_error("Problem creating thread\n"); + } + + int done = 0; + // Now wait for the threads to come back, and also kick off new ones + while(donedone) { + parm[i]->done = 0; + done++; + codegen_response_t *response = (codegen_response_t*)parm[i]->response; + char *json = make_json_string(response); + print_json_to_screen(json, count, done); + if (response->codegen) { + delete response->codegen; + } + free(parm[i]->response); + free(json); + // More to do? Start a new one on this just finished thread + if(still_left >= 0) { parm[i]->tag = still_left; - parm[i]->duration = duration; - parm[i]->done = 0; + parm[i]->filename = (char*)files[still_left].c_str(); still_left--; - pthread_attr_init(&attr[i]); - pthread_attr_setdetachstate(&attr[i], PTHREAD_CREATE_DETACHED); - // Kick off the thread - if (pthread_create(&t[i], &attr[i], threaded_codegen_file, (void*)parm[i])) - throw std::runtime_error("Problem creating thread\n"); - } + int err= pthread_create(&t[i], &attr[i], threaded_codegen_file, (void*)parm[i]); + if(err) + throw std::runtime_error("Problem creating thread\n"); - int done = 0; - // Now wait for the threads to come back, and also kick off new ones - while(donedone) { - parm[i]->done = 0; - done++; - codegen_response_t *response = (codegen_response_t*)parm[i]->response; - char *json = make_json_string(response); - print_json_to_screen(json, count, done); - if (response->codegen) { - delete response->codegen; - } - free(parm[i]->response); - free(json); - // More to do? Start a new one on this just finished thread - if(still_left >= 0) { - parm[i]->tag = still_left; - parm[i]->filename = (char*)files[still_left].c_str(); - still_left--; - int err= pthread_create(&t[i], &attr[i], threaded_codegen_file, (void*)parm[i]); - if(err) - throw std::runtime_error("Problem creating thread\n"); - - } - } - } + } } + } + } - // Clean up threads - for(int i=0;i #include #include @@ -27,9 +28,9 @@ ROUND_FUNC(double,) inline void gettimeofday(struct timeval* t,void* timezone) { struct _timeb timebuffer; - _ftime( &timebuffer ); - t->tv_sec=timebuffer.time; - t->tv_usec=1000*timebuffer.millitm; + _ftime_s( &timebuffer ); + t->tv_sec = timebuffer.time; + t->tv_usec = 1000*timebuffer.millitm; } inline double rint( double x) diff --git a/windows/codegen.vs2015.sln b/windows/codegen.vs2015.sln new file mode 100644 index 0000000..48a1ecf --- /dev/null +++ b/windows/codegen.vs2015.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "codegen.vs2015", "codegen.vs2015.vcxproj", "{9B5D2654-C9B8-4DBC-BD77-4466EB5DF9CC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9B5D2654-C9B8-4DBC-BD77-4466EB5DF9CC}.Debug|Win32.ActiveCfg = Debug|Win32 + {9B5D2654-C9B8-4DBC-BD77-4466EB5DF9CC}.Debug|Win32.Build.0 = Debug|Win32 + {9B5D2654-C9B8-4DBC-BD77-4466EB5DF9CC}.Release|Win32.ActiveCfg = Release|Win32 + {9B5D2654-C9B8-4DBC-BD77-4466EB5DF9CC}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/windows/codegen.vs2015.vcxproj b/windows/codegen.vs2015.vcxproj new file mode 100644 index 0000000..5079432 --- /dev/null +++ b/windows/codegen.vs2015.vcxproj @@ -0,0 +1,116 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {9B5D2654-C9B8-4DBC-BD77-4466EB5DF9CC} + Win32Proj + codegen + + + + Application + true + Unicode + v140 + + + Application + false + true + Unicode + + + + + + + + + + + + + true + $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;$(LIB) + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(INCLUDES) + + + false + + + + NotUsing + Level3 + Disabled + WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;CODEGEN_EXPORTS;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + + + Console + true + %(AdditionalLibraryDirectories) + tag.lib;E:\dev\tools\lib\zlib\zlib.lib;%(AdditionalDependencies) + /STACK:100000000 %(AdditionalOptions) + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;CODEGEN_EXPORTS;BOOST_UBLAS_NDEBUG;%(PreprocessorDefinitions) + ..\taglib-1.7\include;..\taglib-1.7;..\zlib-1.2.5;..\boost_1_46_1;%(AdditionalIncludeDirectories) + + + Console + true + true + true + ..\zlib-1.2.5\Release;..\taglib-1.7\taglib\Release;%(AdditionalLibraryDirectories) + tag.lib;zlib.lib;%(AdditionalDependencies) + /STACK:100000000 %(AdditionalOptions) + + + + + + \ No newline at end of file