Bump echoprint version to 5d9847d86e513ca943e7

This commit is contained in:
John Maguire 2011-06-29 14:58:16 +00:00
parent c7fef47e61
commit 55b001c400
25 changed files with 425 additions and 347 deletions

View File

@ -1,8 +1,26 @@
echoprint-codegen was written by
See the LICENSE file for important license information.
Whitening, SubbandAnalysis, Fingerprint
Dan Ellis <dpwe@ee.columbia.edu>
Brian Whitman <brian@echonest.com>
AudioBufferInput, AudioStreamInput, Codegen, Common, File, MatrixUtility, Metadata
Tristan Jehan <tristan@echonest.com>
Paul Lamere <paul@echonest.com>
Jason Sundram <jsundram@gmail.com>
Brian Whitman <brian@echonest.com>
Murmurhash2
Austin Appleby
Base64
Rene Nyffenegger
Contributors
Alastair Porter <alastair@porter.net.nz>
and is Copyright 2011 The Echo Nest Corporation.
efsavage
alsuren
artgillespie
yhorng
divan

View File

@ -10,15 +10,25 @@ There are two modes of operation of the Echoprint codegen:
2. the codegen binary runs standalone, accepts filenames as inputs and runs in a multithreaded worker mode.
## Requirements for libcodegen
## Requirements
### For libcodegen
* Boost >= 1.35
* zlib
## Additional requirements for the codegen binary
### Additional requirements for the codegen binary
* [TagLib](http://developer.kde.org/~wheeler/taglib.html "TagLib")
* ffmpeg - this is called via shell and is not linked into codegen
On Ubuntu or Debian you can install these dependencies with:
sudo apt-get install ffmpeg libboost1.42-dev libtag1-dev zlib1g-dev
On OS-X with homebrew you can use:
brew install ffmpeg boost taglib
## Notes about libcodegen:
Code generation takes a buffer of floating point PCM data sampled at 11025 Hz and mono.

View File

@ -18,11 +18,12 @@ void AudioBufferInput::SetBuffer(const float* pBuffer, uint numSamples) {
memcpy(_pSamples, pBuffer, numSamples*sizeof(float));
}
void AudioBufferInput::SaveBuffer(const char*filename) {
void AudioBufferInput::SaveBuffer(const char*filename) {
FILE *out = fopen(filename,"wb");
fwrite(&_NumberSamples, sizeof(int), 1, out);
uint mn = 1;
fwrite(&mn, sizeof(int), 1, out);
fwrite(_pSamples, 4, _NumberSamples, out);
fclose(out);
}
}

View File

@ -10,27 +10,21 @@
#include <iostream>
#include <string>
#include <vector>
#ifdef _WIN32
#ifndef _WIN32
#include <unistd.h>
#define POPEN_MODE "r"
#else
#include "win_unistd.h"
#include <winsock.h>
#define POPEN_MODE "rb"
#else
#define POPEN_MODE "r"
#endif
#if defined(_WIN32) && !defined(__MINGW32__)
#include "win_unistd.h"
#else
#include <unistd.h>
#endif
#include <string.h>
#include "AudioStreamInput.h"
#include "Common.h"
#include "Params.h"
using std::string;
using std::string;
namespace FFMPEG {
// Do we think FFmpeg will read this as an audio file?
@ -41,7 +35,7 @@ namespace FFMPEG {
if (File::ends_with(pFileName, supportedExtensions[i]))
return true;
}
return false;
return false;
}
}
@ -60,20 +54,20 @@ AudioStreamInput::~AudioStreamInput() {
bool AudioStreamInput::ProcessFile(const char* filename, int offset_s/*=0*/, int seconds/*=0*/) {
if (!File::Exists(filename) || !IsSupported(filename))
return false;
_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)
if (ok)
{
bool did_work = ProcessFilePointer(fp);
bool succeeded = !pclose(fp);
ok = did_work && succeeded;
}
else
}
else
fprintf(stderr, "AudioStreamInput::ProcessFile can't open %s\n", filename);
return ok;
@ -83,16 +77,16 @@ bool AudioStreamInput::ProcessFile(const char* filename, int offset_s/*=0*/, int
bool AudioStreamInput::ProcessRawFile(const char* rawFilename) {
FILE* fp = fopen(rawFilename, "r"); // TODO: Windows
bool ok = (fp != NULL);
if (ok)
if (ok)
{
ok = ProcessFilePointer(fp);
fclose(fp);
}
return ok;
}
// reads raw signed 16-bit shorts from stdin, for example:
// 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.
@ -114,7 +108,7 @@ bool AudioStreamInput::ProcessFilePointer(FILE* pFile) {
uint sampleCounter = 0;
_pSamples = new float[_NumberSamples];
uint samplesLeft = _NumberSamples;
for (uint i = 0; i < vChunks.size(); i++)
for (uint i = 0; i < vChunks.size(); i++)
{
short* pChunk = vChunks[i];
uint numSamples = samplesLeft < nSamplesPerChunk ? samplesLeft : nSamplesPerChunk;
@ -134,3 +128,5 @@ bool AudioStreamInput::ProcessFilePointer(FILE* pFile) {
perror("ProcessFilePointer error");
return success;
}

View File

@ -20,20 +20,20 @@
class AudioStreamInput {
public:
AudioStreamInput();
virtual ~AudioStreamInput();
virtual ~AudioStreamInput();
virtual bool ProcessFile(const char* filename, int offset_s=0, int seconds=0);
virtual std::string GetName() = 0;
bool ProcessRawFile(const char* rawFilename);
bool ProcessStandardInput(void);
bool ProcessFilePointer(FILE* pFile);
int getNumSamples() const {return _NumberSamples;}
const float* getSamples() {return _pSamples;}
const float* getSamples() {return _pSamples;}
double getDuration() { return (double)getNumSamples() / Params::AudioStreamInput::SamplingRate; }
virtual bool IsSupported(const char* pFileName); //Everything ffmpeg can do, by default
int GetOffset() const { return _Offset_s;}
int GetSeconds() const { return _Seconds;}
protected:
virtual std::string GetCommandLine(const char* filename) = 0;
static bool ends_with(const char *s, const char *ends_with);
float* _pSamples;
@ -44,19 +44,19 @@ protected:
};
class StdinStreamInput : public AudioStreamInput {
public:
public:
std::string GetName(){return "stdin";};
protected:
bool IsSupported(const char* pFileName){ return (std::string("stdin") == pFileName);};
bool ProcessFile(const char* filename, int offset_s=0, int seconds=0){ return ProcessStandardInput();}
bool ProcessFile(const char* filename){ return ProcessStandardInput();}
virtual std::string GetCommandLine(const char* filename){return "";} // hack
};
class FfmpegStreamInput : public AudioStreamInput {
public:
public:
std::string GetName(){return "ffmpeg";};
protected:
std::string GetCommandLine(const char* filename) {
std::string GetCommandLine(const char* filename) {
// TODO: Windows
char message[4096] = {0};
if (_Offset_s == 0 and _Seconds == 0)
@ -65,8 +65,7 @@ protected:
else
snprintf(message, NELEM(message), "ffmpeg -i \"%s\" -ac %d -ar %d -f s16le -t %d -ss %d - 2>/dev/null",
filename, Params::AudioStreamInput::Channels, (uint) Params::AudioStreamInput::SamplingRate, _Seconds, _Offset_s);
printf("%s\n", message);
return std::string(message);
}
};
@ -76,12 +75,12 @@ namespace FFMPEG {
};
class Mpg123StreamInput : public AudioStreamInput {
public:
public:
std::string GetName(){return "mpg123";};
protected:
#define FRAMES_PER_SECOND 38.2813f
bool IsSupported(const char* pFileName){ return File::ends_with(pFileName, ".mp3");};
std::string GetCommandLine(const char* filename) {
std::string GetCommandLine(const char* filename) {
char message[4096] = {0};
if (_Offset_s == 0 and _Seconds == 0)
snprintf(message, NELEM(message), "mpg123 --quiet --singlemix --stdout --rate %d \"%s\"",
@ -94,3 +93,5 @@ protected:
};
#endif

View File

@ -1,4 +1,4 @@
/*
/*
base64.cpp and base64.h
Copyright (C) 2004-2008 René Nyffenegger
@ -28,12 +28,12 @@
#include "Base64.h"
#include <iostream>
static const std::string base64_chars =
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static const std::string base64_chars_url =
static const std::string base64_chars_url =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789-_";
@ -67,7 +67,7 @@ std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_
if (url)
ret += base64_chars_url[char_array_4[i]];
else
ret += base64_chars[char_array_4[i]];
ret += base64_chars[char_array_4[i]];
}
i = 0;
}
@ -87,7 +87,7 @@ std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_
if (url)
ret += base64_chars_url[char_array_4[j]];
else
ret += base64_chars[char_array_4[j]];
ret += base64_chars[char_array_4[j]];
}
while((i++ < 3))
ret += '=';
@ -137,4 +137,5 @@ std::string base64_decode(std::string const& encoded_string) {
}
return ret;
}
}

View File

@ -6,4 +6,5 @@
std::string base64_encode(unsigned char const* , unsigned int len, bool url);
std::string base64_decode(std::string const& s);
#endif
#endif

View File

@ -7,21 +7,33 @@
#include <sstream>
#include <iostream>
#include <iomanip>
#include <memory>
#include "Codegen.h"
#include "AudioBufferInput.h"
#include "Fingerprint.h"
#include "Whitening.h"
#include "SubbandAnalysis.h"
#include "Fingerprint.h"
#include "Common.h"
#include "Base64.h"
#include <zlib.h>
#define VERSION 4.11
using namespace std;
float Codegen::getVersion() {
return VERSION;
}
Codegen::Codegen(const float* pcm, uint 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);
pWhitening->Compute();
AudioBufferInput *pAudio = new AudioBufferInput();
pAudio->SetBuffer(pWhitening->getWhitenedSamples(), pWhitening->getNumSamples());
@ -30,7 +42,7 @@ Codegen::Codegen(const float* pcm, uint numSamples, int start_offset) {
Fingerprint *pFingerprint = new Fingerprint(pSubbandAnalysis, start_offset);
pFingerprint->Compute();
_CodeString = createCodeString(pFingerprint->getCodes());
_NumCodes = pFingerprint->getCodes().size();
@ -48,7 +60,7 @@ string Codegen::createCodeString(vector<FPCode> vCodes) {
codestream << std::setfill('0') << std::hex;
for (uint i = 0; i < vCodes.size(); i++)
codestream << std::setw(5) << vCodes[i].frame;
for (uint i = 0; i < vCodes.size(); i++) {
int hash = vCodes[i].code;
codestream << std::setw(5) << hash;

View File

@ -8,17 +8,10 @@
#define CODEGEN_H
// Entry point for generating codes from PCM data.
#define VERSION 4.11
#include <memory>
#include <string>
#include "Common.h"
#include "AudioBufferInput.h"
#include "SubbandAnalysis.h"
#include "Fingerprint.h"
using namespace std;
#include <vector>
#include <sys/types.h>
#ifdef _MSC_VER
#ifdef CODEGEN_EXPORTS
@ -33,20 +26,22 @@ using namespace std;
#endif
class Fingerprint;
class SubbandAnalysis;
struct FPCode;
class CODEGEN_API Codegen {
public:
Codegen(const float* pcm, uint numSamples, int start_offset);
Codegen(const float* pcm, unsigned int numSamples, int start_offset);
string getCodeString(){return _CodeString;}
std::string getCodeString(){return _CodeString;}
int getNumCodes(){return _NumCodes;}
float getVersion() { return VERSION; }
static float getVersion();
private:
Fingerprint* computeFingerprint(SubbandAnalysis *pSubbandAnalysis, int start_offset);
string createCodeString(vector<FPCode> vCodes);
std::string createCodeString(std::vector<FPCode> vCodes);
string compress(const string& s);
string _CodeString;
std::string compress(const std::string& s);
std::string _CodeString;
int _NumCodes;
};

View File

@ -11,17 +11,17 @@
#include <assert.h>
#ifndef _WIN32
#include <sys/time.h>
#include <sys/time.h>
#else
#include "win_funcs.h"
#include <sys/types.h>
/* for STL*/
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
#include <malloc.h>
#endif
#include <float.h>
@ -43,13 +43,13 @@ static inline double now (void) {
return now;
}
typedef unsigned int uint;
typedef unsigned int uint;
#define NELEM(array) (sizeof(array) / sizeof(array[0]))
#ifndef _WIN32
#define EN_ARRAY(type,var,size) type var[size]
#define EN_ARRAY(type,var,size) type var[size]
#else
#define EN_ARRAY(type,var,size) type* var = (type*) _alloca((size)*sizeof(type))
#define EN_ARRAY(type,var,size) type* var = (type*) _alloca((size)*sizeof(type))
#endif
#endif

View File

@ -7,14 +7,9 @@
#ifndef FILE_H
#define FILE_H
#include <string.h>
#if defined(_WIN32) && !defined(__MINGW32__)
#ifdef _WIN32
#include "win_unistd.h"
#endif
#ifdef __MINGW32__
#include <io.h> // For F_OK
#endif
/*
This makes file writing a bit easier (makes sure we don't forget to fclose, basically). Use it like this:

View File

@ -11,40 +11,40 @@
unsigned int MurmurHash2 ( const void * key, int len, unsigned int seed ) {
// MurmurHash2, by Austin Appleby http://sites.google.com/site/murmurhash/
// m and r are constants set by austin
const unsigned int m = 0x5bd1e995;
const int r = 24;
// Initialize the hash to a 'random' value
unsigned int h = seed ^ len;
// Mix 4 bytes at a time into the hash
const unsigned char * data = (const unsigned char *)key;
while(len >= 4) {
unsigned int k = *(unsigned int *)data;
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
data += 4;
len -= 4;
}
// Handle the last few bytes of the input array
switch(len) {
case 3: h ^= data[2] << 16;
case 2: h ^= data[1] << 8;
case 1: h ^= data[0];
h *= m;
};
const unsigned int m = 0x5bd1e995;
const int r = 24;
// Initialize the hash to a 'random' value
unsigned int h = seed ^ len;
// Mix 4 bytes at a time into the hash
const unsigned char * data = (const unsigned char *)key;
while(len >= 4) {
unsigned int k = *(unsigned int *)data;
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
data += 4;
len -= 4;
}
// Do a few final mixes of the hash to ensure the last few
// bytes are well-incorporated.
h ^= h >> 13;
h *= m;
h ^= h >> 15;
return h;
// Handle the last few bytes of the input array
switch(len) {
case 3: h ^= data[2] << 16;
case 2: h ^= data[1] << 8;
case 1: h ^= data[0];
h *= m;
};
// Do a few final mixes of the hash to ensure the last few
// bytes are well-incorporated.
h ^= h >> 13;
h *= m;
h ^= h >> 15;
return h;
}
Fingerprint::Fingerprint(SubbandAnalysis* pSubbandAnalysis, int offset)
Fingerprint::Fingerprint(SubbandAnalysis* pSubbandAnalysis, int offset)
: _pSubbandAnalysis(pSubbandAnalysis), _Offset(offset) { }
@ -69,19 +69,20 @@ uint Fingerprint::adaptiveOnsets(int ttarg, matrix_u&out, uint*&onset_counter_fo
int nc = floor((float)E.size2()/(float)hop)-(floor((float)nsm/(float)hop)-1);
matrix_f Eb = matrix_f(nc, 8);
MatrixUtility::clear(Eb);
for(uint r=0;r<Eb.size1();r++) for(uint c=0;c<Eb.size2();c++) Eb(r,c) = 0.0;
for(i=0;i<nc;i++) {
for(j=0;j<SUBBANDS;j++) {
for(k=0;k<nsm;k++) Eb(i,j) = Eb(i,j) + ( E(j,(i*hop)+k) * ham[k]);
Eb(i,j) = sqrtf(Eb(i,j));
}
}
frames = Eb.size1();
bands = Eb.size2();
frames = Eb.size1();
bands = Eb.size2();
pE = &Eb.data()[0];
out = matrix_u(SUBBANDS, frames);
out = matrix_u(SUBBANDS, frames);
onset_counter_for_band = new uint[SUBBANDS];
double bn[] = {0.1883, 0.4230, 0.3392}; /* preemph filter */ // new
@ -97,13 +98,13 @@ uint Fingerprint::adaptiveOnsets(int ttarg, matrix_u&out, uint*&onset_counter_fo
contact[j] = 0;
lcontact[j] = 0;
tsince[j] = 0;
Y0[j] = 0;
Y0[j] = 0;
}
for (i = 0; i < frames; ++i) {
for (j = 0; j < SUBBANDS; ++j) {
for (j = 0; j < SUBBANDS; ++j) {
double xn = 0;
double xn = 0;
/* calculate the filter - FIR part */
if (i >= 2*nbn) {
for (int k = 0; k < nbn; ++k) {
@ -117,21 +118,21 @@ uint Fingerprint::adaptiveOnsets(int ttarg, matrix_u&out, uint*&onset_counter_fo
contact[j] = (xn > H[j])? 1 : 0;
if (contact[j] == 1 && lcontact[j] == 0) {
/* attach - record the threshold level unless we have one */
if(N[j] == 0) {
N[j] = H[j];
}
}
if (contact[j] == 1) {
/* update with new threshold */
if (contact[j] == 1 && lcontact[j] == 0) {
/* attach - record the threshold level unless we have one */
if(N[j] == 0) {
N[j] = H[j];
}
}
if (contact[j] == 1) {
/* update with new threshold */
H[j] = xn * overfact;
} else {
/* apply decays */
H[j] = H[j] * exp(-1.0/(double)taus[j]);
}
} else {
/* apply decays */
H[j] = H[j] * exp(-1.0/(double)taus[j]);
}
if (contact[j] == 0 && lcontact[j] == 1) {
if (contact[j] == 0 && lcontact[j] == 1) {
/* detach */
if (onset_counter_for_band[j] > 0 && (int)out(j, onset_counter_for_band[j]-1) > i - deadtime) {
// overwrite last-written time
@ -140,23 +141,23 @@ uint Fingerprint::adaptiveOnsets(int ttarg, matrix_u&out, uint*&onset_counter_fo
}
out(j, onset_counter_for_band[j]++) = i;
++onset_counter;
tsince[j] = 0;
}
++tsince[j];
if (tsince[j] > ttarg) {
taus[j] = taus[j] - 1;
if (taus[j] < 1) taus[j] = 1;
} else {
taus[j] = taus[j] + 1;
}
tsince[j] = 0;
}
++tsince[j];
if (tsince[j] > ttarg) {
taus[j] = taus[j] - 1;
if (taus[j] < 1) taus[j] = 1;
} else {
taus[j] = taus[j] + 1;
}
if ( (contact[j] == 0) && (tsince[j] > deadtime)) {
/* forget the threshold where we recently hit */
N[j] = 0;
}
lcontact[j] = contact[j];
}
pE += bands;
if ( (contact[j] == 0) && (tsince[j] > deadtime)) {
/* forget the threshold where we recently hit */
N[j] = 0;
}
lcontact[j] = contact[j];
}
pE += bands;
}
return onset_counter;
@ -184,15 +185,15 @@ void Fingerprint::Compute() {
uint onset_count = adaptiveOnsets(345, out, onset_counter_for_band);
_Codes.resize(onset_count*6);
for(unsigned char band=0;band<SUBBANDS;band++) {
for(unsigned char band=0;band<SUBBANDS;band++) {
if (onset_counter_for_band[band]>2) {
for(uint onset=0;onset<onset_counter_for_band[band]-2;onset++) {
// What time was this onset at?
uint time_for_onset_ms_quantized = quantized_time_for_frame_absolute(out(band,onset));
uint p[2][6];
int nhashes = 6;
if ((int)onset == (int)onset_counter_for_band[band]-4) { nhashes = 3; }
if ((int)onset == (int)onset_counter_for_band[band]-3) { nhashes = 1; }
p[0][0] = (out(band,onset+1) - out(band,onset));
@ -230,8 +231,8 @@ void Fingerprint::Compute() {
}
}
}
_Codes.resize(actual_codes);
_Codes.resize(actual_codes);
delete [] onset_counter_for_band;
}

View File

@ -1,7 +1,6 @@
UNAME := $(shell uname -s)
CXX=g++
CC=gcc
ARCH=`uname -m`
#OPTFLAGS=-g -O0
OPTFLAGS=-O3 -DBOOST_UBLAS_NDEBUG -DNDEBUG
CXXFLAGS=-Wall -I/usr/local/include/boost-1_35 `taglib-config --cflags` -fPIC $(OPTFLAGS)
@ -19,15 +18,19 @@ MODULES_LIB = \
Whitening.o
MODULES = $(MODULES_LIB) Metadata.o
main: $(MODULES) main.o
$(CXX) $(MODULES) $(LDFLAGS) main.o -o ../echoprint-codegen
all: libcodegen echoprint-codegen
libcodegen: $(MODULES_LIB)
$(CXX) -shared -fPIC -o libcodegen.so $(MODULES_LIB) -lz
ifeq ($(UNAME),Darwin)
libtool -dynamic -flat_namespace -install_name libcodegen.4.1.1.dylib -lSystem -compatibility_version 4.1 -macosx_version_min 10.6 \
-current_version 4.1.1 -o libcodegen.4.1.1.dylib -undefined suppress \
$(MODULES) -framework vecLib -framework Accelerate
-current_version 4.1.1 -o libcodegen.4.1.1.dylib -undefined suppress \
$(MODULES_LIB) -framework vecLib -framework Accelerate
endif
echoprint-codegen: $(MODULES) main.o
$(CXX) $(MODULES) $(LDFLAGS) main.o -o ../echoprint-codegen
%.o: %.c %.h
$(CC) $(CFLAGS) -c -o $@ $<
@ -46,3 +49,13 @@ clean:
ifeq ($(UNAME),Darwin)
rm -f *.dylib
endif
PREFIX ?= /usr/local
# todo: dylib
install: all
install ../echoprint-codegen $(PREFIX)/bin
install -d $(PREFIX)/include/echoprint
install -m 644 Codegen.h $(PREFIX)/include/echoprint
install -m 644 libcodegen.so $(PREFIX)/lib
.PHONY: clean all libcodegen echoprint-codegen install

View File

@ -17,7 +17,7 @@ bool TextFileOutput(const matrix_f& A, const char* filename) {
if (success) {
const float *d = &A.data()[0];
for (uint i = 0; i < A.size1(); i++) {
for (uint j = 0; j < A.size2(); j++)
for (uint j = 0; j < A.size2(); j++)
fprintf(matrix_file, "%2.3f ", d[i*A.size2() + j]);
fprintf(matrix_file, "\n");
@ -31,11 +31,11 @@ bool FileOutput(const matrix_f& A, const char* filename) {
FILE *matrix_file = fopen(filename, "wb");
bool success = (matrix_file != NULL);
if (success) {
uint mm = A.size1();
uint mm = A.size1();
uint mn = A.size2();
fwrite(&mm, sizeof(int), 1, matrix_file);
fwrite(&mn, sizeof(int), 1, matrix_file);
for (uint i = 0; i< A.size1(); i++) {
for(uint j=0;j<A.size2(); j++) {
const float d = A(i, j);
@ -47,8 +47,6 @@ bool FileOutput(const matrix_f& A, const char* filename) {
return success;
}
void clear(matrix_f A) {
for(uint i=0;i<A.size1();i++) for(uint j=0;j<A.size2();j++) A(i,j) = 0.0;
}
} // namespace

View File

@ -9,10 +9,10 @@
#define MATRIXUTILITY_H
#include "Common.h"
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/matrix_proxy.hpp>
namespace ublas = boost::numeric::ublas;
namespace ublas = boost::numeric::ublas;
typedef ublas::matrix<float> matrix_f;
typedef ublas::matrix<uint> matrix_u;
@ -27,6 +27,5 @@ namespace MatrixUtility {
inline uint cols(matrix_f A){ return A.size2();}
bool FileOutput(const matrix_f& A, const char* filename);
bool TextFileOutput(const matrix_f& A, const char* filename);
void clear(matrix_f A);
}
#endif

View File

@ -13,7 +13,7 @@ Metadata::Metadata(const string& file) : _Filename(file), _Artist(""), _Album(""
if (file != "stdin") {
// 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) {
_Artist = tag->artist().toCString();
@ -21,7 +21,7 @@ Metadata::Metadata(const string& file) : _Filename(file), _Artist(""), _Album(""
_Title = tag->title().toCString();
_Genre = tag->genre().toCString();
}
TagLib::AudioProperties* properties = f.isNull() ? NULL : f.audioProperties();
if (properties != NULL) {
_Bitrate = properties->bitrate();

View File

@ -29,9 +29,10 @@ private:
string _Album;
string _Title;
string _Genre;
int _Bitrate;
int _SampleRate;
int _Seconds;
};
#endif
#endif

View File

@ -13,7 +13,7 @@ SubbandAnalysis::SubbandAnalysis(AudioStreamInput* pAudio) {
Init();
}
SubbandAnalysis::SubbandAnalysis(const float* pSamples, uint numSamples) :
SubbandAnalysis::SubbandAnalysis(const float* pSamples, uint numSamples) :
_pSamples(pSamples), _NumSamples(numSamples) {
Init();
}
@ -28,17 +28,17 @@ void SubbandAnalysis::Init() {
for (uint i = 0; i < M_ROWS; ++i) {
for (uint k = 0; k < 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));
_Mi(i,k) = sin((2*i + 1)*(k-4)*(M_PI/16.0));
}
}
}
void SubbandAnalysis::Compute() {
uint t, i, j;
float Z[C_LEN];
float Y[M_COLS];
_NumFrames = (_NumSamples - C_LEN + 1)/SUBBANDS;
assert(_NumFrames > 0);
@ -55,7 +55,7 @@ void SubbandAnalysis::Compute() {
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 < M_ROWS; ++i) {
float Dr = 0, Di = 0;

View File

@ -18,21 +18,21 @@
namespace SubbandFilterBank {
// 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,
0.000019550, 0.000027657, 0.000037670, 0.000049591, 0.000062943, 0.000076771, 0.000090599, 0.000101566,
-0.000108242, -0.000106812, -0.000095367, -0.000069618, -0.000027180, 0.000034332, 0.000116348, 0.000218868,
0.000339031, 0.000472546, 0.000611782, 0.000747204, 0.000866413, 0.000954151, 0.000994205, 0.000971317,
-0.000868797, -0.000674248, -0.000378609, 0.000021458, 0.000522137, 0.001111031, 0.001766682, 0.002457142,
0.003141880, 0.003771782, 0.004290581, 0.004638195, 0.004752159, 0.004573822, 0.004049301, 0.003134727,
-0.001800537, -0.000033379, 0.002161503, 0.004756451, 0.007703304, 0.010933399, 0.014358521, 0.017876148,
0.021372318, 0.024725437, 0.027815342, 0.030526638, 0.032754898, 0.034412861, 0.035435200, 0.035780907,
-0.035435200, -0.034412861, -0.032754898, -0.030526638, -0.027815342, -0.024725437, -0.021372318, -0.017876148,
-0.014358521, -0.010933399, -0.007703304, -0.004756451, -0.002161503, 0.000033379, 0.001800537, 0.003134727,
-0.004049301, -0.004573822, -0.004752159, -0.004638195, -0.004290581, -0.003771782, -0.003141880, -0.002457142,
-0.001766682, -0.001111031, -0.000522137, -0.000021458, 0.000378609, 0.000674248, 0.000868797, 0.000971317,
-0.000994205, -0.000954151, -0.000866413, -0.000747204, -0.000611782, -0.000472546, -0.000339031, -0.000218868,
-0.000116348, -0.000034332, 0.000027180, 0.000069618, 0.000095367, 0.000106812, 0.000108242, 0.000101566,
-0.000090599, -0.000076771, -0.000062943, -0.000049591, -0.000037670, -0.000027657, -0.000019550, -0.000013828,
0.000000477, 0.000000954, 0.000001431, 0.000002384, 0.000003815, 0.000006199, 0.000009060, 0.000013828,
0.000019550, 0.000027657, 0.000037670, 0.000049591, 0.000062943, 0.000076771, 0.000090599, 0.000101566,
-0.000108242, -0.000106812, -0.000095367, -0.000069618, -0.000027180, 0.000034332, 0.000116348, 0.000218868,
0.000339031, 0.000472546, 0.000611782, 0.000747204, 0.000866413, 0.000954151, 0.000994205, 0.000971317,
-0.000868797, -0.000674248, -0.000378609, 0.000021458, 0.000522137, 0.001111031, 0.001766682, 0.002457142,
0.003141880, 0.003771782, 0.004290581, 0.004638195, 0.004752159, 0.004573822, 0.004049301, 0.003134727,
-0.001800537, -0.000033379, 0.002161503, 0.004756451, 0.007703304, 0.010933399, 0.014358521, 0.017876148,
0.021372318, 0.024725437, 0.027815342, 0.030526638, 0.032754898, 0.034412861, 0.035435200, 0.035780907,
-0.035435200, -0.034412861, -0.032754898, -0.030526638, -0.027815342, -0.024725437, -0.021372318, -0.017876148,
-0.014358521, -0.010933399, -0.007703304, -0.004756451, -0.002161503, 0.000033379, 0.001800537, 0.003134727,
-0.004049301, -0.004573822, -0.004752159, -0.004638195, -0.004290581, -0.003771782, -0.003141880, -0.002457142,
-0.001766682, -0.001111031, -0.000522137, -0.000021458, 0.000378609, 0.000674248, 0.000868797, 0.000971317,
-0.000994205, -0.000954151, -0.000866413, -0.000747204, -0.000611782, -0.000472546, -0.000339031, -0.000218868,
-0.000116348, -0.000034332, 0.000027180, 0.000069618, 0.000095367, 0.000106812, 0.000108242, 0.000101566,
-0.000090599, -0.000076771, -0.000062943, -0.000049591, -0.000037670, -0.000027657, -0.000019550, -0.000013828,
-0.000009060, -0.000006199, -0.000003815, -0.000002384, -0.000001431, -0.000000954, -0.000000477, 0};
}
@ -42,14 +42,14 @@ class SubbandAnalysis {
public:
inline SubbandAnalysis() {};
SubbandAnalysis(AudioStreamInput* pAudio);
SubbandAnalysis(const float* pSamples, uint numSamples);
SubbandAnalysis(const float* pSamples, uint numSamples);
virtual ~SubbandAnalysis();
void Compute();
public:
inline uint getNumFrames() const {return _NumFrames;}
inline uint getNumBands() const {return SUBBANDS;}
const matrix_f& getMatrix() {return _Data;}
const matrix_f& getMatrix() {return _Data;}
protected:
const float* _pSamples;
uint _NumSamples;

View File

@ -13,7 +13,7 @@ Whitening::Whitening(AudioStreamInput* pAudio) {
Init();
}
Whitening::Whitening(const float* pSamples, uint numSamples) :
Whitening::Whitening(const float* pSamples, uint numSamples) :
_pSamples(pSamples), _NumSamples(numSamples) {
Init();
}
@ -27,16 +27,16 @@ Whitening::~Whitening() {
void Whitening::Init() {
int i;
_P = 40;
_R = (float *)malloc((_P+1)*sizeof(float));
for (i = 0; i <= _P; ++i) { _R[i] = 0.0; }
_R[0] = 0.001;
_Xo = (float *)malloc((_P+1)*sizeof(float));
for (i = 0; i < _P; ++i) { _Xo[i] = 0.0; }
_p = 40;
_ai = (float *)malloc((_P+1)*sizeof(float));
_R = (float *)malloc((_p+1)*sizeof(float));
for (i = 0; i <= _p; ++i) { _R[i] = 0.0; }
_R[0] = 0.001;
_Xo = (float *)malloc((_p+1)*sizeof(float));
for (i = 0; i < _p; ++i) { _Xo[i] = 0.0; }
_ai = (float *)malloc((_p+1)*sizeof(float));
_whitened = (float*) malloc(sizeof(float)*_NumSamples);
}
@ -57,23 +57,23 @@ void Whitening::ComputeBlock(int start, int blockSize) {
float T = 8;
alpha = 1.0/T;
// calculate autocorrelation of current block
for (i = 0; i <= _P; ++i) {
// calculate autocorrelation of current block
for (i = 0; i <= _p; ++i) {
float acc = 0;
for (j = 0; j < (int)blockSize; ++j) {
if (j >= i) {
acc += _pSamples[j+start] * _pSamples[j-i+start];
}
}
// smoothed update
// smoothed update
_R[i] += alpha*(acc - _R[i]);
}
// calculate new filter coefficients
// Durbin's recursion, per p. 411 of Rabiner & Schafer 1978
// calculate new filter coefficients
// Durbin's recursion, per p. 411 of Rabiner & Schafer 1978
E = _R[0];
for (i = 1; i <= _P; ++i) {
for (i = 1; i <= _p; ++i) {
float sumalphaR = 0;
for (j = 1; j < i; ++j) {
sumalphaR += _ai[j]*_R[i-j];
@ -88,21 +88,21 @@ void Whitening::ComputeBlock(int start, int blockSize) {
}
E = (1-ki*ki)*E;
}
// calculate new output
// calculate new output
for (i = 0; i < (int)blockSize; ++i) {
float acc = _pSamples[i+start];
for (j = 1; j <= _P; ++j) {
for (j = 1; j <= _p; ++j) {
if (i-j < 0) {
acc -= _ai[j]*_Xo[_P + i-j];
acc -= _ai[j]*_Xo[_p + i-j];
} else {
acc -= _ai[j]*_pSamples[i-j+start];
}
}
_whitened[i+start] = acc;
}
// save last few frames of input
for (i = 0; i <= _P; ++i) {
_Xo[i] = _pSamples[blockSize-1-_P+i+start];
// save last few frames of input
for (i = 0; i <= _p; ++i) {
_Xo[i] = _pSamples[blockSize-1-_p+i+start];
}
}

View File

@ -17,15 +17,15 @@ class Whitening {
public:
inline Whitening() {};
Whitening(AudioStreamInput* pAudio);
Whitening(const float* pSamples, uint numSamples);
Whitening(const float* pSamples, uint numSamples);
virtual ~Whitening();
void Compute();
void ComputeBlock(int start, int blockSize);
public:
float* getWhitenedSamples() const {return _whitened;}
inline uint getNumSamples() const {return _NumSamples;}
protected:
const float* _pSamples;
float* _whitened;
@ -33,7 +33,7 @@ protected:
float* _R;
float *_Xo;
float *_ai;
int _P;
int _p;
private:
void Init();
};

View File

@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
9AAF51A713B2557800099790 /* Whitening.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 9AAF51A513B2557800099790 /* Whitening.cxx */; };
9AAF51A813B2557800099790 /* Whitening.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AAF51A613B2557800099790 /* Whitening.h */; };
9AE5AA19139FB2620009FCD8 /* SubbandAnalysis.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AE5AA17139FB2620009FCD8 /* SubbandAnalysis.h */; };
9AE5AA1A139FB2620009FCD8 /* SubbandAnalysis.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 9AE5AA18139FB2620009FCD8 /* SubbandAnalysis.cxx */; };
C8D4AD20137EE85F00CD506D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C8D4AD1F137EE85F00CD506D /* Foundation.framework */; };
@ -30,6 +32,8 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
9AAF51A513B2557800099790 /* Whitening.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Whitening.cxx; path = ../Whitening.cxx; sourceTree = SOURCE_ROOT; };
9AAF51A613B2557800099790 /* Whitening.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Whitening.h; path = ../Whitening.h; sourceTree = SOURCE_ROOT; };
9AE5AA17139FB2620009FCD8 /* SubbandAnalysis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SubbandAnalysis.h; path = ../SubbandAnalysis.h; sourceTree = SOURCE_ROOT; };
9AE5AA18139FB2620009FCD8 /* SubbandAnalysis.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SubbandAnalysis.cxx; path = ../SubbandAnalysis.cxx; sourceTree = SOURCE_ROOT; };
C8D4AD1C137EE85F00CD506D /* libechoprint-codegen-ios.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libechoprint-codegen-ios.a"; sourceTree = BUILT_PRODUCTS_DIR; };
@ -98,6 +102,8 @@
C8D4AD21137EE85F00CD506D /* echoprint-codegen-ios */ = {
isa = PBXGroup;
children = (
9AAF51A513B2557800099790 /* Whitening.cxx */,
9AAF51A613B2557800099790 /* Whitening.h */,
9AE5AA17139FB2620009FCD8 /* SubbandAnalysis.h */,
9AE5AA18139FB2620009FCD8 /* SubbandAnalysis.cxx */,
C8D4AD29137EF41100CD506D /* AudioBufferInput.cxx */,
@ -109,7 +115,6 @@
C8D4AD2F137EF41100CD506D /* Codegen.cxx */,
C8D4AD30137EF41100CD506D /* Codegen.h */,
C8D4AD31137EF41100CD506D /* Common.h */,
C8D4AD3A137EF41100CD506D /* fft */,
C8D4AD40137EF41100CD506D /* File.h */,
C8D4AD42137EF41100CD506D /* Fingerprint.cxx */,
C8D4AD43137EF41100CD506D /* Fingerprint.h */,
@ -131,14 +136,6 @@
name = "Supporting Files";
sourceTree = "<group>";
};
C8D4AD3A137EF41100CD506D /* fft */ = {
isa = PBXGroup;
children = (
);
name = fft;
path = ../../fft;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@ -158,6 +155,7 @@
C8D4AD6D137EF41100CD506D /* win_funcs.h in Headers */,
C8D4AD6E137EF41100CD506D /* win_unistd.h in Headers */,
9AE5AA19139FB2620009FCD8 /* SubbandAnalysis.h in Headers */,
9AAF51A813B2557800099790 /* Whitening.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -215,6 +213,7 @@
C8D4AD62137EF41100CD506D /* Fingerprint.cxx in Sources */,
C8D4AD64137EF41100CD506D /* MatrixUtility.cxx in Sources */,
9AE5AA1A139FB2620009FCD8 /* SubbandAnalysis.cxx in Sources */,
9AAF51A713B2557800099790 /* Whitening.cxx in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -20,18 +20,30 @@
#include <string>
#define MAX_FILES 200000
#ifdef _WIN32
#include <pthread.h>
#endif
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;
} codegen_response_t;
// Struct to pass to the worker threads
typedef struct {
char *filename;
char *filename;
int start_offset;
int duration;
int done ;
int tag;
char *output;
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
@ -68,8 +80,6 @@ int getNumCores() {
#endif
}
using namespace std;
// deal with quotes etc in json
std::string escape(const string& value) {
std::string s(value);
@ -79,7 +89,7 @@ std::string escape(const string& value) {
char c = s[i];
if (c <= 31)
continue;
switch (c) {
case '"' : out += "\\\""; break;
case '\\': out += "\\\\"; break;
@ -94,78 +104,63 @@ std::string escape(const string& value) {
// TODO: do something with unicode?
}
}
return out;
}
char* json_string_for_file(char* filename, int start_offset, int duration, int tag) {
// Given a filename, do all the work to get a JSON string output.
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;
auto_ptr<FfmpegStreamInput> 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\"}}",
tag,
sprintf(output,"{\"error\":\"could not create decoder\", \"tag\":%d, \"metadata\":{\"filename\":\"%s\"}}",
tag,
escape(filename).c_str());
return output;
response->error = output;
return response;
}
int numSamples = pAudio->getNumSamples();
if (numSamples < 1) {
char* output = (char*) malloc(16384);
sprintf(output,"{\"error\":\"could not decode\", \"tag\":%d, \"metadata\":{\"filename\":\"%s\"}}",
tag,
sprintf(output,"{\"error\":\"could not decode\", \"tag\":%d, \"metadata\":{\"filename\":\"%s\"}}",
tag,
escape(filename).c_str());
return output;
response->error = output;
return response;
}
t1 = now() - t1;
double t2 = now();
auto_ptr<Codegen> pCodegen(new Codegen(pAudio->getSamples(), numSamples, start_offset));
Codegen *pCodegen = new Codegen(pAudio->getSamples(), numSamples, start_offset);
t2 = now() - t2;
// Get the ID3 tag information.
auto_ptr<Metadata> pMetadata(new Metadata(filename));
// preamble + codelen
char* output = (char*) malloc(sizeof(char)*(16384 + strlen(pCodegen->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(filename).c_str(),
numSamples,
duration,
start_offset,
pCodegen->getVersion(),
t2,
t1,
pCodegen->getNumCodes(),
pCodegen->getCodeString().c_str(),
tag
);
return output;
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;
}
void *threaded_json_string_for_file(void *parm) {
void *threaded_codegen_file(void *parm) {
// pthread stub to invoke json_string_for_file
thread_parm_t *p = (thread_parm_t *)parm;
char * output = json_string_for_file(p->filename, p->start_offset, p->duration, p->tag);
p->output = output;
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;
@ -179,13 +174,49 @@ void print_json_to_screen(char* output, int count, int done) {
else printf("%s,\n", output);
}
char *make_json_string(codegen_response_t* response) {
if (response->error != NULL) {
return response->error;
}
// Get the ID3 tag information.
auto_ptr<Metadata> 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);
}
try {
string files[MAX_FILES];
char *filename = argv[1];
@ -209,23 +240,24 @@ int main(int argc, char** argv) {
}
}
} else files[count++] = filename;
if(count == 0) throw std::runtime_error("No files given.\n");
#ifdef _WIN32
//#ifdef __APPLE__
fprintf(stderr, "no thread mode\n");
// Threading doesn't work in windows yet.
for(int i=0;i<count;i++) {
char* output = json_string_for_file((char*)files[i].c_str(), start_offset, duration, i);
codegen_response_t* response = codegen_file((char*)files[i].c_str(), start_offset, duration, i);
char *output = make_json_string(response);
print_json_to_screen(output, count, i);
free(output);
}
return 1;
#endif
// FIgure out how many threads to use based on # of cores
#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;
@ -239,7 +271,7 @@ int main(int argc, char** argv) {
// Kick off the first N threads
int still_left = count-1-already;
for(int i=0;i<num_threads;i++) {
parm[i] = (thread_parm_t *)malloc(sizeof(thread_parm_t));
parm[i] = (thread_parm_t *)malloc(sizeof(thread_parm_t));
parm[i]->filename = (char*)files[still_left].c_str();
parm[i]->start_offset = start_offset;
parm[i]->tag = still_left;
@ -249,10 +281,10 @@ int main(int argc, char** argv) {
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_json_string_for_file, (void*)parm[i]))
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(done<count) {
@ -261,20 +293,22 @@ int main(int argc, char** argv) {
if (parm[i]->done) {
parm[i]->done = 0;
done++;
print_json_to_screen(parm[i]->output, count, done);
free(parm[i]->output);
codegen_response_t *response = (codegen_response_t*)parm[i]->response;
char *json = make_json_string(response);
print_json_to_screen(json, count, done);
free(parm[i]->response);
// 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_json_string_for_file, (void*)parm[i]);
if(err)
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
@ -285,6 +319,8 @@ int main(int argc, char** argv) {
free(parm);
free(attr);
return 0;
#endif // _WIN32
}
catch(std::runtime_error& ex) {
fprintf(stderr, "%s\n", ex.what());

View File

@ -7,15 +7,15 @@
#define ROUND_FUNC(type,suff) inline type round##suff(type x) \
{ \
if (x >= 0.0##suff){ \
type y = floor##suff(x); \
if (x - y >= 0.5##suff) \
y += 1.0##suff; \
return y; \
if (x >= 0.0##suff){ \
type y = floor##suff(x); \
if (x - y >= 0.5##suff) \
y += 1.0##suff; \
return y; \
}else{ \
type y = ceil##suff(x); \
if (y - x >= 0.5##suff) \
y -= 1.0##suff; \
type y = ceil##suff(x); \
if (y - x >= 0.5##suff) \
y -= 1.0##suff; \
return y; \
} \
}

View File

@ -1,36 +1,37 @@
#ifndef _UNISTD_H
#define _UNISTD_H 1
/* This file intended to serve as a drop-in replacement for
* unistd.h on Windows
* Please add functionality as neeeded
http://stackoverflow.com/questions/341817/is-there-a-replacement-for-unistd-h-for-windows-visual-c
*/
#include <stdlib.h>
#include <io.h>
/*
#include <getopt.h>
getopt from: http://www.pwilson.net/sample.html. */
#define srandom srand
#define random rand
const int F_OK = 0;
const int W_OK = 2;
const int R_OK = 4;
#define access _access
#define ftruncate _chsize
/* stdio */
#define popen _popen
#define pclose _pclose
/* float.h */
#define finite _finite
#define ssize_t int
#endif /* unistd.h */
#ifndef _UNISTD_H
#define _UNISTD_H 1
/* This file intended to serve as a drop-in replacement for
* unistd.h on Windows
* Please add functionality as neeeded
http://stackoverflow.com/questions/341817/is-there-a-replacement-for-unistd-h-for-windows-visual-c
*/
#include <stdlib.h>
#include <io.h>
/*
#include <getopt.h>
getopt from: http://www.pwilson.net/sample.html. */
#define srandom srand
#define random rand
#define F_OK 0
#define W_OK 2
#define R_OK 4
#define access _access
#define ftruncate _chsize
/* stdio */
#define popen _popen
#define pclose _pclose
/* float.h */
#define finite _finite
#define ssize_t int
#endif /* unistd.h */