Last active
February 13, 2018 21:26
-
-
Save hertzg/c75aa10072d10f00b38e to your computer and use it in GitHub Desktop.
compare_acoustid.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require('fs') | |
let fp1Map = parseFPStr(fs.readFileSync('fpcalc.mp3.fp').toString('utf8')) | |
, fp2Map = parseFPStr(fs.readFileSync('fpcalc-16.mp3.fp').toString('utf8')) | |
; | |
function parseFPStr(fpStr) { | |
let lines = fpStr.split('\n') | |
, map = Object.create(null) | |
; | |
lines.forEach(function(line){ | |
let parts = line.split('='); | |
map[parts.shift()] = parts.join('='); | |
}); | |
map['FINGERPRINT'] = map['FINGERPRINT'].split(',').map(parseFloat); | |
return map; | |
} | |
const ACOUSTID_MAX_ALIGN_OFFSET = 120 | |
, ACOUSTID_MAX_BIT_ERROR = 2 | |
; | |
const POPCOUNT_TABLE_8BIT = [ | |
0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, | |
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, | |
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, | |
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, | |
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, | |
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, | |
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, | |
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 | |
]; | |
function popcount_lookup8(x) { | |
return POPCOUNT_TABLE_8BIT[ x & 0xff ] + | |
POPCOUNT_TABLE_8BIT[ (x >> 8) & 0xff ] + | |
POPCOUNT_TABLE_8BIT[ (x >> 16) & 0xff ] + | |
POPCOUNT_TABLE_8BIT[ x >> 24 ]; | |
} | |
function calculate_distance(fp1Arr, fp2Arr) { | |
//must be one dimensional array | |
//TODO: check | |
//both Must have data | |
//TODO: check return 0 | |
let totalLength = fp1Arr.length + fp2Arr.length + 1 | |
, counts = Array.apply(null, new Array(totalLength)).map(Number.prototype.valueOf, 0) | |
; | |
console.log('FP1.length=%d FP2.length=%d', fp1Arr.length, fp2Arr.length); | |
for(let i=0; i<fp1Arr.length; i++) { | |
let jMin = Math.max(0, i-ACOUSTID_MAX_ALIGN_OFFSET) | |
, jMax = Math.min(fp2Arr.length, i+ACOUSTID_MAX_ALIGN_OFFSET); | |
; | |
for(let j=jMin; j<jMax; j++) { | |
let bitErr = popcount_lookup8(fp1Arr[i] ^ fp2Arr[j]); | |
//console.log('%s xor %s = %s', fp1Arr[i].toString(2), fp2Arr[j].toString(2), bitErr.toString(2)); | |
//console.log("comparing %d and %d with error %d", i, j, bitErr); | |
if(bitErr <= ACOUSTID_MAX_BIT_ERROR) { | |
let offset = i - j + fp2Arr.length; | |
counts[offset] += 1; | |
} | |
} | |
} | |
//console.log(counts.join(',')) | |
let maxCount = Math.max.apply(Math, counts) | |
, minLength = Math.min(fp1Arr.length, fp2Arr.length) | |
return 1 - (maxCount / (1* minLength )); | |
} | |
console.log('Calculating distance from from "%s" to "%s"', fp1Map.FILE, fp2Map.FILE); | |
console.log('Distance=%s', calculate_distance(fp1Map.FINGERPRINT, fp2Map.FINGERPRINT)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
hello hertzg
how much would you charge for implementing the same code with the aggrate framework in mongo db