Updates
This commit is contained in:
parent
e324be7268
commit
510e5ccc90
3
Makefile
3
Makefile
|
|
@ -1,4 +1,7 @@
|
|||
-include .config
|
||||
|
||||
CFLAGS += -Wall -MMD
|
||||
LDLIBS += -lm
|
||||
|
||||
tempo: tempo.o
|
||||
|
||||
|
|
|
|||
142
tempo.c
142
tempo.c
|
|
@ -1,7 +1,13 @@
|
|||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sysexits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define BANNER "tempo 0.1 (C) Copyright 2011 Mark Hills <mark@pogo.org.uk>"
|
||||
#define NAME "tempo"
|
||||
|
||||
#define RATE 44100 /* of input data */
|
||||
|
||||
|
|
@ -13,27 +19,21 @@
|
|||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
|
||||
|
||||
/*
|
||||
* Sample from the metered energy with interpolation
|
||||
* Sample from the metered energy
|
||||
*
|
||||
* No need to interpolate and it makes a tiny amount of difference; we
|
||||
* take a random sample of samples, any errors are averaged out.
|
||||
*/
|
||||
|
||||
static double sample(float nrg[], size_t len, double offset)
|
||||
{
|
||||
double f, a, b;
|
||||
size_t n;
|
||||
double n;
|
||||
size_t i;
|
||||
|
||||
n = (size_t)offset;
|
||||
n = floor(offset);
|
||||
i = (size_t)n;
|
||||
|
||||
f = offset - n;
|
||||
if (f == 0.0)
|
||||
return (n < len) ? nrg[n] : 0.0;
|
||||
|
||||
/* Linear interpolation */
|
||||
|
||||
a = (n < len) ? nrg[n] : 0.0;
|
||||
n++;
|
||||
b = (n < len) ? nrg[n] : 0.0;
|
||||
|
||||
return (1.0 - f) * a + f * b;
|
||||
return (n >= 0.0 && n < (double)len) ? nrg[i] : 0.0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -43,22 +43,28 @@ static double sample(float nrg[], size_t len, double offset)
|
|||
double autodifference(float nrg[], size_t len, double interval)
|
||||
{
|
||||
size_t n;
|
||||
double mid, v, diff = 0.0;
|
||||
static const int beats[] = { -32, -16, -8, -4, -4, -4, -2, -2, -1,
|
||||
1, 2, 2, 4, 4, 4, 8, 16, 32 };
|
||||
double mid, v, diff;
|
||||
static const double beats[] = { -32, -16, -8, -4, -2, -1, 1, 2, 4, 8, 16, 32 },
|
||||
nobeats[] = { -0.5, -0.25, 0.25, 0.5 };
|
||||
|
||||
mid = drand() * len;
|
||||
v = sample(nrg, len, mid);
|
||||
|
||||
diff = 0.0;
|
||||
for (n = 0; n < ARRAY_SIZE(beats); n++) {
|
||||
int beat;
|
||||
double y;
|
||||
|
||||
beat = beats[n];
|
||||
y = sample(nrg, len, mid + beat * interval);
|
||||
y = sample(nrg, len, mid + beats[n] * interval);
|
||||
diff += fabs(y - v);
|
||||
}
|
||||
|
||||
for (n = 0; n < ARRAY_SIZE(nobeats); n++) {
|
||||
double y;
|
||||
|
||||
y = sample(nrg, len, mid + nobeats[n] * interval);
|
||||
diff -= fabs(y - v);
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +102,8 @@ double interval_to_bpm(double interval)
|
|||
double scan_for_bpm(float nrg[], size_t len,
|
||||
double slowest, double fastest,
|
||||
unsigned int steps,
|
||||
unsigned int samples)
|
||||
unsigned int samples,
|
||||
bool graph)
|
||||
{
|
||||
double step, interval, trough, height;
|
||||
unsigned int s;
|
||||
|
|
@ -107,17 +114,16 @@ double scan_for_bpm(float nrg[], size_t len,
|
|||
|
||||
height = INFINITY;
|
||||
|
||||
for (;;) {
|
||||
for (interval = fastest; interval <= slowest; interval += step) {
|
||||
double t;
|
||||
|
||||
interval += step;
|
||||
if (interval > slowest)
|
||||
break;
|
||||
|
||||
t = 0.0;
|
||||
for (s = 0; s < samples; s++)
|
||||
t += autodifference(nrg, len, interval);
|
||||
|
||||
if (graph)
|
||||
printf("%lf\t%lf\n", interval_to_bpm(interval), t);
|
||||
|
||||
/* Track the lowest value */
|
||||
|
||||
if (t < height) {
|
||||
|
|
@ -129,13 +135,70 @@ double scan_for_bpm(float nrg[], size_t len,
|
|||
return interval_to_bpm(trough - (step / 2));
|
||||
}
|
||||
|
||||
void usage(FILE *f)
|
||||
{
|
||||
fprintf(f, "Usage: " NAME " [options]\n"
|
||||
"Analyse the tempo (in beats-per-minute, BPM) of incoming audio\n\n"
|
||||
" -g Output autodifference graph to stdout\n"
|
||||
" -f Print format for final BPM value (default \"%%0.1f\")\n"
|
||||
" -v Print progress information to stderr\n"
|
||||
" -h Display this help message and exit\n\n");
|
||||
|
||||
fprintf(f, "Incoming audio is raw audio at %dHz, mono, 32-bit float; eg.\n"
|
||||
" sox file.mp3 -t raw -r %d -e float -c 1 | ./" NAME "\n",
|
||||
RATE, RATE);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
float *nrg = NULL;
|
||||
size_t len = 0, buf = 0;
|
||||
off_t n = 0;
|
||||
double bpm;
|
||||
float v = 0.0;
|
||||
float bpm, v = 0.0;
|
||||
const char *format = "%0.1f";
|
||||
bool verbose = false;
|
||||
|
||||
for (;;) {
|
||||
int c;
|
||||
|
||||
c = getopt(argc, argv, "vf:gh");
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
format = optarg;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
format = NULL;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage(stdout);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return EX_USAGE;
|
||||
}
|
||||
}
|
||||
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
if (argc > 0) {
|
||||
fprintf(stderr, "%s: Too many arguments\n", NAME);
|
||||
return EX_USAGE;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
fputs(BANNER "\n", stderr);
|
||||
fprintf(stderr, "Metering incoming audio\n");
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
float z;
|
||||
|
|
@ -164,21 +227,32 @@ int main(int argc, char *argv[])
|
|||
if (len == buf) {
|
||||
size_t n;
|
||||
|
||||
fprintf(stderr, "Reallocating at %zd\n", len);
|
||||
|
||||
n = buf + BLOCK;
|
||||
nrg = realloc(nrg, n * sizeof(*nrg));
|
||||
assert(nrg != NULL);
|
||||
if (nrg == NULL) {
|
||||
perror("realloc");
|
||||
return -1;
|
||||
}
|
||||
buf = n;
|
||||
}
|
||||
|
||||
nrg[len++] = v;
|
||||
}
|
||||
|
||||
bpm = scan_for_bpm(nrg, len, 60.0, 180.0, 400, 1000);
|
||||
printf("BPM = %f\n", bpm);
|
||||
if (verbose)
|
||||
fprintf(stderr, "Sampling tempo range\n");
|
||||
|
||||
bpm = scan_for_bpm(nrg, len, 60.0, 180.0, 400, 1000, (format == NULL));
|
||||
|
||||
if (format != NULL) {
|
||||
printf(format, bpm);
|
||||
putc('\n', stdout);
|
||||
}
|
||||
|
||||
free(nrg);
|
||||
|
||||
if (verbose)
|
||||
fprintf(stderr, "Done\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue