/*
pHash, the open source perceptual hash library
Copyright (C) 2009 Aetilius, Inc.
All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Evan Klinger - eklinger@phash.org
David Starkweather - dstarkweather@phash.org
*/
#include "audiophash.h"
#include
#include
#ifdef HAVE_LIBMPG123
#include
#endif
int ph_count_samples(const char *filename, int sr,int channels){
SF_INFO sf_info;
sf_info.format=0;
SNDFILE *sndfile = sf_open(filename, SFM_READ, &sf_info);
if (sndfile == NULL){
return NULL;
}
int count = sf_info.frames;
sf_close(sndfile);
return count;
}
#ifdef HAVE_LIBMPG123
static
float* readaudio_mp3(const char *filename,long *sr, const float nbsecs, unsigned int *buflen){
mpg123_handle *m;
int ret;
if (mpg123_init() != MPG123_OK || ((m = mpg123_new(NULL,&ret)) == NULL)|| \
mpg123_open(m, filename) != MPG123_OK){
fprintf(stderr,"unable to init mpg\n");
return NULL;
}
/*turn off logging */
mpg123_param(m, MPG123_ADD_FLAGS, MPG123_QUIET, 0);
off_t totalsamples;
mpg123_scan(m);
totalsamples = mpg123_length(m);
int meta = mpg123_meta_check(m);
int channels, encoding;
if (mpg123_getformat(m, sr, &channels, &encoding) != MPG123_OK){
fprintf(stderr,"unable to get format\n");
return NULL;
}
mpg123_format_none(m);
mpg123_format(m, *sr, channels, encoding);
size_t decbuflen = mpg123_outblock(m);
unsigned char *decbuf = (unsigned char*)malloc(decbuflen);
if (decbuf == NULL){
printf("mem alloc error\n");
return NULL;
}
unsigned int nbsamples = (nbsecs <= 0) ? totalsamples : nbsecs*(*sr);
nbsamples = (nbsamples < totalsamples) ? nbsamples : totalsamples;
size_t i, j, index = 0, done;
float *buffer = (float*)malloc(nbsamples*sizeof(float));
*buflen = nbsamples;
do {
ret = mpg123_read(m, decbuf, decbuflen, &done);
switch (encoding) {
case MPG123_ENC_SIGNED_16 :
for (i = 0; i < done/sizeof(short); i+=channels){
buffer[index] = 0.0f;
for (j = 0; j < channels ; j++){
buffer[index] += (float)(((short*)decbuf)[i+j])/(float)SHRT_MAX;
}
buffer[index++] /= channels;
if (index >= nbsamples) break;
}
break;
case MPG123_ENC_SIGNED_8:
for (i = 0; i < done/sizeof(char); i+=channels){
buffer[index] = 0.0f;
for (j = 0; j < channels ; j++){
buffer[index] += (float)(((char*)decbuf)[i+j])/(float)SCHAR_MAX;
}
buffer[index++] /= channels;
if (index >= nbsamples) break;
}
break;
case MPG123_ENC_FLOAT_32:
for (i = 0; i < done/sizeof(float); i+=channels){
buffer[index] = 0.0f;
for (j = 0; j < channels; j++){
buffer[index] += ((float*)decbuf)[i+j];
}
buffer[index++] /= channels;
if (index >= nbsamples) break;
}
break;
default:
done = 0;
}
} while (ret == MPG123_OK && index < nbsamples);
free(decbuf);
mpg123_close(m);
mpg123_delete(m);
mpg123_exit();
return buffer;
}
#endif /*HAVE_LIBMPG123*/
static
float *readaudio_snd(const char *filename, long *sr, const float nbsecs, unsigned int *buflen){
SF_INFO sf_info;
sf_info.format=0;
SNDFILE *sndfile = sf_open(filename, SFM_READ, &sf_info);
if (sndfile == NULL){
return NULL;
}
/* normalize */
sf_command(sndfile, SFC_SET_NORM_FLOAT, NULL, SF_TRUE);
*sr = (long)sf_info.samplerate;
//allocate input buffer for signal
unsigned int src_frames = (nbsecs <= 0) ? sf_info.frames : (nbsecs*sf_info.samplerate);
src_frames = (sf_info.frames < src_frames) ? sf_info.frames : src_frames;
float *inbuf = (float*)malloc(src_frames*sf_info.channels*sizeof(float));
/*read frames */
sf_count_t cnt_frames = sf_readf_float(sndfile, inbuf, src_frames);
float *buf = (float*)malloc(cnt_frames*sizeof(float));
//average across all channels
int i,j,indx=0;
for (i=0;i maxF){
maxF = magnF[i];
}
}
for (int i=0;i maxB)
maxB = curr_bark[i];
}
uint32_t curr_hash = 0x00000000u;
for (int m=0;m 0)
curr_hash |= 0x00000001;
}
hash[index] = curr_hash;
for (int i=0;i> 1) & MASK_01010101) ;
n = (n & MASK_00110011) + ((n >> 2) & MASK_00110011) ;
n = (n & MASK_00001111) + ((n >> 4) & MASK_00001111) ;
return n % 255;
}
double ph_compare_blocks(const uint32_t *ptr_blockA,const uint32_t *ptr_blockB, const int block_size){
double result = 0;
for (int i=0;in; ++i)
{
DP *dp = (DP *)s->hash_p[i];
int N, count;
pair *p = (pair *)s->hash_params;
float *buf = ph_readaudio(dp->id, p->first, p->second, NULL, N);
uint32_t *hash = ph_audiohash(buf, N, p->first, count);
free(buf);
buf = NULL;
dp->hash = hash;
dp->hash_length = count;
}
}
DP** ph_audio_hashes(char *files[], int count, int sr, int channels, int threads)
{
if(!files || count == 0)
return NULL;
int num_threads;
if(threads > count)
{
num_threads = count;
}
else if(threads > 0)
{
num_threads = threads;
}
else
{
num_threads = ph_num_threads();
}
DP **hashes = (DP**)malloc(count*sizeof(DP*));
for(int i = 0; i < count; ++i)
{
hashes[i] = (DP *)malloc(sizeof(DP));
hashes[i]->id = strdup(files[i]);
}
pthread_t thds[num_threads];
int rem = count % num_threads;
int start = 0;
int off = 0;
slice *s = new slice[num_threads];
for(int n = 0; n < num_threads; ++n)
{
off = (int)floor((count/(float)num_threads) + (rem>0?num_threads-(count % num_threads):0));
s[n].hash_p = &hashes[start];
s[n].n = off;
s[n].hash_params = new pair(sr,channels);
start += off;
--rem;
pthread_create(&thds[n], NULL, ph_audio_thread, &s[n]);
}
for(int i = 0; i < num_threads; ++i)
{
pthread_join(thds[i], NULL);
delete (pair*)s[i].hash_params;
}
delete[] s;
return hashes;
}
#endif