Skip to content

Instantly share code, notes, and snippets.

@x42
Created November 17, 2021 17:37
Show Gist options
  • Save x42/87600d6e8c3f874f1b52ac8d03bdeeaf to your computer and use it in GitHub Desktop.
Save x42/87600d6e8c3f874f1b52ac8d03bdeeaf to your computer and use it in GitHub Desktop.
// g++ -o /tmp/sf_out sf_out.cc -Wall -lsndfile -lm
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <sndfile.h>
int main (int argc, char** argv)
{
SF_INFO _info;
memset (&_info, 0, sizeof (_info));
_info.channels = 1;
_info.samplerate = 48000;
_info.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
/* tempo ramp */
double bpm_start = 120;
double bpm_end = 60;
uint32_t duration_beats = 16;
/* with 0 <= t <= 1 and bpm_start > bpm_end
* bpm[t] = bpm_start * exp (-t * log (bpm_start / bpm_end))
*
* bpm[t0,t1] = \frac {\int_{t0}^{t1} bpm[t] \,dt}} {t1 - t0}
*/
SNDFILE* sf_out = sf_open ("/tmp/out.wav", SFM_WRITE, &_info);
const float one = 1.0;
const float zero = 0.0;
assert (bpm_start > bpm_end);
const double lg_bpm = log (bpm_start / bpm_end);
for (uint32_t b = 0; b < duration_beats; ++b) {
sf_write_float (sf_out, &one, 1);
double b0 = b / (double) duration_beats;
double b1 = (b + 1) / (double) duration_beats;
double bpm_b0 = bpm_start * exp (-b0 * lg_bpm);
double bpm_b1 = bpm_start * exp (-b1 * lg_bpm);
/* calculate area under exp curve between bpm[b0], bpm[b1], the divide by distance */
double bpm_dist = (1.0 / lg_bpm) * (bpm_b0 - bpm_b1) / (b1 - b0);
int spb = _info.samplerate * 60.0 / bpm_dist;
for (int i = 1; i < spb; ++i) {
sf_write_float (sf_out, &zero, 1);
}
}
/* add fixed beat at the end */
uint32_t spb_end = _info.samplerate * 60 / bpm_end;
for (uint32_t b = 0; b < duration_beats; ++b) {
sf_write_float (sf_out, &one, 1);
for (uint32_t i = 1; i < spb_end; ++i) {
sf_write_float (sf_out, &zero, 1);
}
}
sf_close (sf_out);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment