Skip to content

Commit

Permalink
Very large change. Tweaked the spectrum algorithm slightly so it won'…
Browse files Browse the repository at this point in the history
…t be

affected by endian issues. While I was at it, changed how I sum across the
spectra such that we store the log of the histogram -- lower frequencies have
smaller bands. This required changing how songs are drawn, and also how
inter-song frequency relationships are determined. The "ideal freq" curve
is no longer needed (yay!). It appears to give a better picture of what's
going on, and gives even nifter match-by-freq.

I also increased the fixed-len buffer size to match the largest possible
file size.
  • Loading branch information
cgroom committed Sep 9, 2002
1 parent a83ec66 commit 49593b6
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 53 deletions.
27 changes: 24 additions & 3 deletions analysis.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <sys/poll.h>
#include <vorbis/vorbisfile.h>
#include <vorbis/codec.h>
#include <endian.h>
#include <math.h>
#include "gjay.h"
#include "analysis.h"
Expand All @@ -41,6 +42,8 @@ pthread_mutex_t analyze_data_mutex;
song * analyze_song = NULL;
int analyze_percent = 0;
analyze_mode analyze_state = ANALYZE_IDLE;
gboolean analyze_redraw_freq = FALSE;


typedef enum {
OGG = 0,
Expand All @@ -53,7 +56,6 @@ void * analyze_thread(void* arg);
FILE * inflate_to_wav (gchar * path, ftype type);
FILE * inflate_to_raw (gchar * path, ftype type);


gboolean analyze(song * s) {
pthread_t thread;
if (!(s->flags & ( FREQ_UNK | BPM_UNK)))
Expand Down Expand Up @@ -81,6 +83,7 @@ void * analyze_thread(void* arg) {
pthread_mutex_lock(&analyze_data_mutex);
analyze_song = (song *) arg;
analyze_percent = 0;
analyze_redraw_freq = FALSE;
path = g_strdup(analyze_song->path);
pthread_mutex_unlock(&analyze_data_mutex);

Expand All @@ -93,6 +96,8 @@ void * analyze_thread(void* arg) {
} else {
rewind(f);
fread(&header, sizeof(waveheaderstruct), 1, f);
wav_header_swab(&header);

if ((strncmp(header.chunk_type, "WAVE", 4) == 0) &&
(header.byte_p_spl / header.modus == 2)) {
type = WAV;
Expand Down Expand Up @@ -134,14 +139,15 @@ void * analyze_thread(void* arg) {
analyze_state = ANALYZE_FREQ;
pthread_mutex_unlock(&analyze_data_mutex);
f = inflate_to_wav(path, type);
spectrum(f, fsize, freq);
result = spectrum(f, fsize, freq);
fclose(f);

pthread_mutex_lock(&analyze_data_mutex);
if (analyze_song) {
if (result && analyze_song) {
for (i = 0; i < NUM_FREQ_SAMPLES; i++)
analyze_song->freq[i] = freq[i];
analyze_song->flags -= FREQ_UNK;
analyze_redraw_freq = TRUE;
}
}
pthread_mutex_unlock(&analyze_data_mutex);
Expand Down Expand Up @@ -242,3 +248,18 @@ FILE * inflate_to_wav ( gchar * path,
}


/* Swap the byte order of wav header. Wavs are stored little-endian, so this
is necessary when using on big-endian (e.g. PPC) machines */
void wav_header_swab(waveheaderstruct * header) {
header->length = le32_to_cpu(header->length);
header->length_chunk = le32_to_cpu(header->length_chunk);
header->data_length = le32_to_cpu(header->data_length);
header->sample_fq = le32_to_cpu(header->sample_fq);
header->byte_p_sec = le32_to_cpu(header->byte_p_sec);
header->format = le16_to_cpu(header->format);
header->modus = le16_to_cpu(header->modus);
header->byte_p_spl = le16_to_cpu(header->byte_p_spl);
header->bit_p_spl = le16_to_cpu(header->bit_p_spl);
}


37 changes: 35 additions & 2 deletions analysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,37 @@
#define __ANALYSIS_H__

#include <pthread.h>
#include <stdint.h>

#include "gjay.h"

/* Shamelessly excerpted from the Linux kernel */
#if __BYTE_ORDER == __BIG_ENDIAN
#define le32_to_cpu(x) __swab32((x))
#define le16_to_cpu(x) __swab16((x))
#elif __BYTE_ORDER == __LITTLE_ENDIAN
#define le32_to_cpu(x) ((uint32_t)(x))
#define le16_to_cpu(x) ((uint16_t)(x))
#endif

#define __swab16(x) \
({ \
uint16_t __x = (x); \
((uint16_t)( \
(((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \
(((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \
})
#define __swab32(x) \
({ \
uint32_t __x = (x); \
((uint32_t)( \
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
})


/* This mutex is locked when an analysis is in progress, unlocked
* otherwise. When locked, the song analyze_song shouldn't be
* altered or have its freq data touched */
Expand Down Expand Up @@ -57,15 +86,19 @@ typedef struct {
/* Mutex lock for analysis data */
extern pthread_mutex_t analyze_data_mutex;
extern song * analyze_song;
extern int analyze_percent;
extern analyze_mode analyze_state;
extern int analyze_percent;
extern gboolean analyze_redraw_freq;

/* Analysis.c */
gboolean analyze(song * s);
/* Swap endian-ness */
void wav_header_swab(waveheaderstruct * header);
unsigned long swab_ul(unsigned long l);
unsigned short swab_us(unsigned short s);

/* spectrum.c */
int spectrum (FILE * f, long fsize, gdouble * results);
gdouble ideal_freq (int i);

/* bpm.c */
double bpm (FILE * f, long fsize);
Expand Down
2 changes: 1 addition & 1 deletion gjay.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#define NUM_FREQ_SAMPLES 30

/* Default directory for storing app info */
#define GJAY_VERSION "0.1"
#define GJAY_VERSION "0.1.3"
#define GJAY_DIR ".gjay"
#define GJAY_DATA "gjay_data"
#define GJAY_PREFS "gjay_prefs"
Expand Down
12 changes: 10 additions & 2 deletions playlist.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,17 @@ static gdouble distance ( song * s1 ) {
criteria += prefs.criteria_freq;
d = 0;
for (i = 0; i < NUM_FREQ_SAMPLES; i++) {
d += fabsl(s1->freq[i] - s2->freq[i]) / ideal_freq(i);
d += fabsl(s1->freq[i] - s2->freq[i]);
if (i < NUM_FREQ_SAMPLES - 1) {
d += fabsl(s1->freq[i] - s2->freq[i + 1])/2.0;
d += fabsl(s1->freq[i + 1] - s2->freq[i])/2.0;
}
if (i > 0) {
d += fabsl(s1->freq[i] - s2->freq[i - 1])/2.0;
d += fabsl(s1->freq[i - 1] - s2->freq[i])/2.0;
}
}
d *= prefs.criteria_freq / 25.0;
d *= prefs.criteria_freq / 4.0;
distance += d;
}

Expand Down
11 changes: 7 additions & 4 deletions prefs.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,13 @@ void load_prefs ( void ) {
}
fscanf(in, "%s\n", buffer);
if (strcmp(buffer, GJAY_VERSION)) {
fprintf(stderr, "Unknown file format for version %s; this is version %s\n", buffer, GJAY_VERSION);
default_prefs();
fclose(in);
return;
/* Prefs didn't change from 0.1 */
if (strcmp(buffer, "0.1")) {
fprintf(stderr, "Unknown file format for version %s; this is version %s\n", buffer, GJAY_VERSION);
default_prefs();
fclose(in);
return;
}
}
fread(&prefs, sizeof(app_prefs), 1, in);

Expand Down
36 changes: 22 additions & 14 deletions songs.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <string.h>
#include <vorbis/vorbisfile.h>
#include <vorbis/codec.h>
#include <endian.h>
#include <errno.h>
#include "gjay.h"
#include "analysis.h"
Expand Down Expand Up @@ -61,6 +62,9 @@ void load_songs ( void ) {
int i, k, t, len;
unsigned int n;
long unsigned int ln;
gboolean clear_freq;

clear_freq = FALSE;

snprintf(buffer, BUFFER_SIZE, "%s/%s/%s", getenv("HOME"),
GJAY_DIR, GJAY_DATA);
Expand All @@ -72,8 +76,13 @@ void load_songs ( void ) {

fscanf(in, "%s", buffer);
if (strcmp(buffer, GJAY_VERSION)) {
fprintf(stderr, "Unknown file format for version %s; this is version %s\n", buffer, GJAY_VERSION);
return;
if (strcmp(buffer, "0.1") == 0) {
clear_freq = TRUE;
display_message("This is a newer version of GJay.\nThe frequency analysis has changed.");
} else {
fprintf(stderr, "Unknown file format for version %s; this is version %s\n", buffer, GJAY_VERSION);
return;
}
}

fscanf(in, "%d ", &num_songs);
Expand Down Expand Up @@ -109,6 +118,9 @@ void load_songs ( void ) {
s->length = n;
fscanf(in, "%d ", &t);
s->flags = t;

if (clear_freq)
s->flags |= FREQ_UNK;
songs = g_list_append(songs, s);
}
fclose(in);
Expand Down Expand Up @@ -204,7 +216,7 @@ song * new_song_file ( gchar * fname ) {
s->album = g_strdup ("?");
} else {
snprintf(buffer, BUFFER_SIZE, "Sorry, unable to open '%s'.\n"
"Make sure file is mp3, ogg, or wav", SONG(current)->fname);
"Make sure file is mp3, ogg, or wav", fname);
display_message(buffer);
}
return s;
Expand Down Expand Up @@ -368,13 +380,14 @@ song * test_wav ( char * fname ) {
if (!f)
return NULL;
fread(&header, sizeof(waveheaderstruct), 1, f);
wav_header_swab(&header);
fclose(f);
if ((strncmp(header.chunk_type, "WAVE", 4) == 0) &&
(header.byte_p_spl / header.modus == 2)) {
s = new_song(fname);
stat(fname, & buf);
s->length = (buf.st_size - sizeof(waveheaderstruct)) / 176758;
}
}
return s;
}

Expand Down Expand Up @@ -611,7 +624,7 @@ gint sort_color ( gconstpointer a, gconstpointer b) {
gint sort_freq ( gconstpointer a, gconstpointer b) {
song * s_a = (song *) a;
song * s_b = (song *) b;
gdouble a_sum, b_sum, ideal, a_val, b_val;
gdouble a_sum, b_sum, a_val, b_val;
gint i;

if (s_a->flags & FREQ_UNK) {
Expand All @@ -623,17 +636,12 @@ gint sort_freq ( gconstpointer a, gconstpointer b) {
return 1;

for (i = 0, a_sum = 0, b_sum = 0; i < NUM_FREQ_SAMPLES; i++) {
ideal = ideal_freq(i);
a_val = (s_a->freq[i] - ideal)/ideal;
b_val = (s_b->freq[i] - ideal)/ideal;
if (a_val > 0)
a_val = s_a->freq[i];
b_val = s_b->freq[i];
if (a_val > b_val)
a_sum += a_val;
else
b_sum -= a_val;
if (b_val > 0)
else if (a_val < b_val)
b_sum += b_val;
else
a_sum -= b_val;
}

if (a_sum < b_sum)
Expand Down
Loading

0 comments on commit 49593b6

Please sign in to comment.