Skip to content
This repository was archived by the owner on Mar 28, 2022. It is now read-only.

Commit f986a9e

Browse files
committed
Implemented unhashed codes: zlib urlsafe base64 encoded by default, human readable with -h flag.
Squashed commit of the following: commit bbdd156 commit 4c5c903 commit 13756eb commit 434f442 commit e99df11 commit 005be9e commit afce593 commit f0bc228 commit bd67d66
1 parent 0559ce1 commit f986a9e

File tree

6 files changed

+121
-13
lines changed

6 files changed

+121
-13
lines changed

codegen.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/sh
2+
#
3+
# To make it easy to use with GNU Parallel, e.g.,
4+
# parallel codegen.sh ::: *.mp3
5+
#
6+
echoprint-codegen -h "$1" > "$1.json"

src/Codegen.cxx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ using std::string;
2323
using std::vector;
2424

2525
Codegen::Codegen(const float* pcm, unsigned int numSamples, int start_offset) {
26+
for (int i = 0; i < 2; ++i) {
27+
is_code_string_cached[i] = false;
28+
}
29+
2630
if (Params::AudioStreamInput::MaxSamples < (uint)numSamples)
2731
throw std::runtime_error("File was too big\n");
2832

@@ -38,7 +42,11 @@ Codegen::Codegen(const float* pcm, unsigned int numSamples, int start_offset) {
3842
Fingerprint *pFingerprint = new Fingerprint(pSubbandAnalysis, start_offset);
3943
pFingerprint->Compute();
4044

45+
#if defined(UNHASHED_CODES)
46+
_CodeString = createCodeStringJSON(pFingerprint->getCodes());
47+
#else
4148
_CodeString = createCodeString(pFingerprint->getCodes());
49+
#endif
4250
_NumCodes = pFingerprint->getCodes().size();
4351

4452
delete pFingerprint;
@@ -63,6 +71,27 @@ string Codegen::createCodeString(vector<FPCode> vCodes) {
6371
return compress(codestream.str());
6472
}
6573

74+
string Codegen::createCodeStringJSON(vector<FPCode> vCodes) {
75+
if (vCodes.size() < 3) {
76+
return "";
77+
}
78+
std::ostringstream codestream;
79+
codestream << "[";
80+
for (uint i = 0; i < vCodes.size(); i++) {
81+
int hash = vCodes[i].code;
82+
// codestream << std::setw(5) << hash;
83+
codestream << "[" << vCodes[i].frame << ", "
84+
<< ((hash >> 20) & 7) << ", "
85+
<< ((hash >> 10) & 1023) << ", "
86+
<< ((hash >> 0) & 1023)
87+
<< "]";
88+
if (i < vCodes.size()-1) {
89+
codestream << ", ";
90+
}
91+
}
92+
codestream << "]";
93+
return codestream.str();
94+
}
6695

6796
string Codegen::compress(const string& s) {
6897
long max_compressed_length = s.size()*2;
@@ -89,3 +118,24 @@ string Codegen::compress(const string& s) {
89118
delete [] compressed;
90119
return encoded;
91120
}
121+
122+
std::string Codegen::getCodeString(bool human_readable) {
123+
const uint n = human_readable;
124+
if (!is_code_string_cached[n]) {
125+
is_code_string_cached[n] = true;
126+
if (human_readable) {
127+
if (_CodeString.size() > 0) {
128+
code_string_cache[n] = _CodeString;
129+
} else {
130+
code_string_cache[n] = "[]";
131+
}
132+
} else {
133+
if (_CodeString.size() > 0) {
134+
code_string_cache[n] = '"' + compress(_CodeString) + '"';
135+
} else {
136+
code_string_cache[n] = "\"\"";
137+
}
138+
}
139+
}
140+
return code_string_cache[n];
141+
}

src/Codegen.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,20 @@ class CODEGEN_API Codegen {
3333
public:
3434
Codegen(const float* pcm, unsigned int numSamples, int start_offset);
3535

36-
std::string getCodeString(){return _CodeString;}
36+
std::string getCodeString(bool human_readable);
37+
3738
int getNumCodes(){return _NumCodes;}
3839
static double getVersion() { return ECHOPRINT_VERSION; }
3940
private:
4041
Fingerprint* computeFingerprint(SubbandAnalysis *pSubbandAnalysis, int start_offset);
4142
std::string createCodeString(std::vector<FPCode> vCodes);
43+
std::string createCodeStringJSON(std::vector<FPCode> vCodes);
4244

4345
std::string compress(const std::string& s);
4446
std::string _CodeString;
4547
int _NumCodes;
48+
bool is_code_string_cached[2];
49+
std::string code_string_cache[2];
4650
};
4751

4852
#endif

src/Fingerprint.cxx

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include "win_funcs.h"
1313
#endif
1414

15+
#define SATURATE(var, val) if ((var) > (val)) (var) = (val);
16+
1517
unsigned int MurmurHash2 ( const void * key, int len, unsigned int seed ) {
1618
// MurmurHash2, by Austin Appleby http://sites.google.com/site/murmurhash/
1719
// m and r are constants set by austin
@@ -182,13 +184,18 @@ uint Fingerprint::quantized_time_for_frame_absolute(uint frame) {
182184

183185
void Fingerprint::Compute() {
184186
uint actual_codes = 0;
187+
#if !defined(UNHASHED_CODES)
185188
unsigned char hash_material[5];
186189
for(uint i=0;i<5;i++) hash_material[i] = 0;
190+
#endif
187191
uint * onset_counter_for_band;
188192
matrix_u out;
189193
uint onset_count = adaptiveOnsets(345, out, onset_counter_for_band);
190194
_Codes.resize(onset_count*6);
191195

196+
#if defined(UNHASHED_CODES)
197+
assert(SUBBANDS <= 8);
198+
#endif
192199
for(unsigned char band=0;band<SUBBANDS;band++) {
193200
if (onset_counter_for_band[band]>2) {
194201
for(uint onset=0;onset<onset_counter_for_band[band]-2;onset++) {
@@ -226,12 +233,22 @@ void Fingerprint::Compute() {
226233
// Quantize the time deltas to 23ms
227234
short time_delta0 = (short)quantized_time_for_frame_delta(p[0][k]);
228235
short time_delta1 = (short)quantized_time_for_frame_delta(p[1][k]);
236+
uint hashed_code;
237+
#if defined(UNHASHED_CODES)
238+
assert(time_delta0 <= 1023);
239+
assert(time_delta1 <= 1023);
240+
#if defined(NDEBUG)
241+
SATURATE(time_delta0, 1023);
242+
SATURATE(time_delta1, 1023);
243+
#endif
244+
hashed_code = ((band & 7) << 20) | ((time_delta0 & 1023) << 10) | (time_delta1 & 1023);
245+
#else
229246
// Create a key from the time deltas and the band index
230247
memcpy(hash_material+0, (const void*)&time_delta0, 2);
231248
memcpy(hash_material+2, (const void*)&time_delta1, 2);
232249
memcpy(hash_material+4, (const void*)&band, 1);
233-
uint hashed_code = MurmurHash2(&hash_material, 5, HASH_SEED) & HASH_BITMASK;
234-
250+
hashed_code = MurmurHash2(&hash_material, 5, HASH_SEED) & HASH_BITMASK;
251+
#endif
235252
// Set the code alongside the time of onset
236253
_Codes[actual_codes++] = FPCode(time_for_onset_ms_quantized, hashed_code);
237254
//fprintf(stderr, "whee %d,%d: [%d, %d] (%d, %d), %d = %u at %d\n", actual_codes, k, time_delta0, time_delta1, p[0][k], p[1][k], band, hashed_code, time_for_onset_ms_quantized);

src/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ VERSION_COMPAT := $(word 1, $(EP_VERSION)).$(word 2, $(EP_VERSION))
77
UNAME := $(shell uname -s)
88
CXX=g++
99
CC=gcc
10-
#OPTFLAGS=-g -O0
11-
OPTFLAGS=-O3 -DBOOST_UBLAS_NDEBUG -DNDEBUG
10+
#OPTFLAGS=-g -O0 -DUNHASHED_CODES
11+
OPTFLAGS=-O3 -DBOOST_UBLAS_NDEBUG -DNDEBUG -DUNHASHED_CODES
1212
BOOST_CFLAGS=-I/usr/local/include/boost-1_35
1313
TAGLIB_CFLAGS=`taglib-config --cflags`
1414
TAGLIB_LIBS=`taglib-config --libs`

src/main.cxx

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -172,15 +172,15 @@ void print_json_to_screen(char* output, int count, int done) {
172172
if(done==1 && count>1) {
173173
printf("[\n%s,\n", output);
174174
} else if(done==1 && count == 1) {
175-
printf("[\n%s\n]\n", output);
175+
printf("%s\n", output);
176176
} else if(done == count) {
177177
printf("%s\n]\n", output);
178178
} else {
179179
printf("%s,\n", output);
180180
}
181181
}
182182

183-
char *make_json_string(codegen_response_t* response) {
183+
char *make_json_string(codegen_response_t* response, bool human_readable_code) {
184184

185185
if (response->error != NULL) {
186186
return response->error;
@@ -190,12 +190,12 @@ char *make_json_string(codegen_response_t* response) {
190190
auto_ptr<Metadata> pMetadata(new Metadata(response->filename));
191191

192192
// preamble + codelen
193-
char* output = (char*) malloc(sizeof(char)*(16384 + strlen(response->codegen->getCodeString().c_str()) ));
193+
char* output = (char*) malloc(sizeof(char)*(16384 + strlen(response->codegen->getCodeString(human_readable_code).c_str()) ));
194194

195195
sprintf(output,"{\"metadata\":{\"artist\":\"%s\", \"release\":\"%s\", \"title\":\"%s\", \"genre\":\"%s\", \"bitrate\":%d,"
196196
"\"sample_rate\":%d, \"duration\":%d, \"filename\":\"%s\", \"samples_decoded\":%d, \"given_duration\":%d,"
197197
" \"start_offset\":%d, \"version\":%2.2f, \"codegen_time\":%2.6f, \"decode_time\":%2.6f}, \"code_count\":%d,"
198-
" \"code\":\"%s\", \"tag\":%d}",
198+
" \"code\":%s, \"tag\":%d}",
199199
escape(pMetadata->Artist()).c_str(),
200200
escape(pMetadata->Album()).c_str(),
201201
escape(pMetadata->Title()).c_str(),
@@ -211,15 +211,45 @@ char *make_json_string(codegen_response_t* response) {
211211
response->t2,
212212
response->t1,
213213
response->codegen->getNumCodes(),
214-
response->codegen->getCodeString().c_str(),
214+
response->codegen->getCodeString(human_readable_code).c_str(),
215215
response->tag
216216
);
217217
return output;
218218
}
219219

220+
// Return true if has specified flag, false otherwise. Remove specified flags.
221+
bool extract_flag(int* p_argc, char*** p_argv, const char* flag) {
222+
int argc = *p_argc;
223+
char** const argv = *p_argv;
224+
for (int i = 1; i < argc; ++i) {
225+
if (strcmp(flag, argv[i]) == 0) {
226+
for (int k = i+1; k < argc; ++k) {
227+
*(*p_argv+k-1) = *(*p_argv+k);
228+
}
229+
--argc;
230+
}
231+
}
232+
const bool changed = (*p_argc != argc);
233+
*p_argc = argc;
234+
return changed;
235+
}
236+
237+
bool take_human_readable_flag(int* p_argc, char*** p_argv) {
238+
return extract_flag(p_argc, p_argv, "-h");
239+
}
240+
220241
int main(int argc, char** argv) {
242+
const bool human_readable_code = take_human_readable_flag(&argc, &argv);
243+
221244
if (argc < 2) {
222-
fprintf(stderr, "Usage: %s [ filename | -s ] [seconds_start] [seconds_duration] [< file_list (if -s is set)]\n", argv[0]);
245+
const char left_margin[] = " ";
246+
fprintf(stderr,
247+
"Usage:\n"
248+
"%s%s [ filename | -s ] [seconds_start] [seconds_duration] "
249+
"[< file_list (if -s is set)]\n",
250+
left_margin, argv[0]);
251+
fputs("OPTIONS\n", stderr);
252+
fprintf(stderr, "%s-h\tHuman-readable code (in contrast to the default""base64 encoded zlib compressed code)\n", left_margin);
223253
exit(-1);
224254
}
225255

@@ -254,7 +284,8 @@ int main(int argc, char** argv) {
254284
// Threading doesn't work in windows yet.
255285
for(int i=0;i<count;i++) {
256286
codegen_response_t* response = codegen_file((char*)files[i].c_str(), start_offset, duration, i);
257-
char *output = make_json_string(response);
287+
char *output = make_json_string(response, human_readable_code
288+
);
258289
print_json_to_screen(output, count, i+1);
259290
if (response->codegen) {
260291
delete response->codegen;
@@ -303,7 +334,7 @@ int main(int argc, char** argv) {
303334
parm[i]->done = 0;
304335
done++;
305336
codegen_response_t *response = (codegen_response_t*)parm[i]->response;
306-
char *json = make_json_string(response);
337+
char *json = make_json_string(response, human_readable_code);
307338
print_json_to_screen(json, count, done);
308339
if (response->codegen) {
309340
delete response->codegen;

0 commit comments

Comments
 (0)