MIDI music player
This commit is contained in:
parent
b953ae2f1d
commit
e57bf668c2
|
@ -43,35 +43,6 @@
|
||||||
#include "limits.h"
|
#include "limits.h"
|
||||||
#include "iir.h"
|
#include "iir.h"
|
||||||
#include "dsp.h"
|
#include "dsp.h"
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
struct dsp_iir make_iir(int cofs, int order)
|
|
||||||
{
|
|
||||||
struct dsp_iir new;
|
|
||||||
new.dcof = calloc(sizeof(float), cofs * order);
|
|
||||||
new.ccof = calloc(sizeof(float), cofs * order);
|
|
||||||
new.dx = calloc(sizeof(float), cofs * order);
|
|
||||||
new.dy = calloc(sizeof(float), cofs * order);
|
|
||||||
new.order = order;
|
|
||||||
new.n = cofs;
|
|
||||||
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct dsp_iir biquad_iir()
|
|
||||||
{
|
|
||||||
struct dsp_iir new = make_iir(3, 1);
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dsp_iir p2_iir_order(int order)
|
|
||||||
{
|
|
||||||
struct dsp_iir new = make_iir(3, order);
|
|
||||||
new.order = order;
|
|
||||||
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
binomial_mult - multiplies a series of binomials together and returns
|
binomial_mult - multiplies a series of binomials together and returns
|
||||||
|
@ -670,105 +641,25 @@ float *fir_bpf(int n, double fcf1, double fcf2)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct dsp_iir sp_lp(double fcf)
|
|
||||||
{
|
|
||||||
struct dsp_iir new = make_iir(2, 1);
|
|
||||||
double x = exp(-2*M_PI*fcf);
|
|
||||||
|
|
||||||
new.ccof[0] = 1 - x;
|
|
||||||
new.ccof[1] = 0.f;
|
|
||||||
|
|
||||||
new.dcof[0] = 0.f;
|
|
||||||
new.dcof[1] = x;
|
|
||||||
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dsp_iir sp_hp(double fcf)
|
|
||||||
{
|
|
||||||
struct dsp_iir new = make_iir(2, 1);
|
|
||||||
double x = exp(-2*M_PI*fcf);
|
|
||||||
|
|
||||||
new.ccof[0] = (1 + x)/2;
|
|
||||||
new.ccof[1] = -new.ccof[0];
|
|
||||||
|
|
||||||
new.dcof[0] = 0.f;
|
|
||||||
new.dcof[1] = x;
|
|
||||||
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* http://www.dspguide.com/ch19/3.htm */
|
|
||||||
struct dsp_iir sp_bp(double fcf, double bw)
|
|
||||||
{
|
|
||||||
double R = 1 - 3*bw;
|
|
||||||
double K = (1 - 2*R*cos(2*M_PI*fcf)+pow(R, 2)) / (2 - 2*cos(2*M_PI*fcf));
|
|
||||||
|
|
||||||
struct dsp_iir new = make_iir(3, 1);
|
|
||||||
|
|
||||||
new.ccof[0] = 1-K;
|
|
||||||
new.ccof[1] = 2*(K-R)*cos(2*M_PI*fcf);
|
|
||||||
new.ccof[2] = pow(R, 2) - K;
|
|
||||||
|
|
||||||
new.dcof[0] = 0.f;
|
|
||||||
new.dcof[1] = 2*R*cos(2*M_PI*fcf);
|
|
||||||
new.dcof[2] = -1 * pow(R, 2);
|
|
||||||
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dsp_iir sp_notch(double fcf, double bw)
|
|
||||||
{
|
|
||||||
double R = 1 - 3*bw;
|
|
||||||
double K = (1 - 2*R*cos(2*M_PI*fcf)+pow(R, 2)) / (2 - 2*cos(2*M_PI*fcf));
|
|
||||||
|
|
||||||
struct dsp_iir new = make_iir(3, 1);
|
|
||||||
|
|
||||||
new.ccof[0] = K;
|
|
||||||
new.ccof[1] = -2*K*cos(2*M_PI*fcf);
|
|
||||||
new.ccof[2] = K;
|
|
||||||
|
|
||||||
new.dcof[0] = 0.f;
|
|
||||||
new.dcof[1] = 2*R*cos(2*M_PI*fcf);
|
|
||||||
new.dcof[2] = -1 * pow(R, 2);
|
|
||||||
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
double chevy_pct_to_e(double pct)
|
|
||||||
{
|
|
||||||
if (pct > 0.292 || pct < 0) {
|
|
||||||
YughWarn("Gave a percentage out of range. Should be between 0.0 and 0.292 to get a proper value. Gave %f.", pct);
|
|
||||||
pct = pct > 0.292 ? 0.292 : 0.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
double e = pow(1/(1-pct), 2) - 1;
|
|
||||||
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Four stage single pole low pass, similar to gauss */
|
|
||||||
/* http://www.dspguide.com/ch19/2.htm */
|
|
||||||
struct dsp_iir sp_lp_gauss(double fcf)
|
|
||||||
{
|
|
||||||
struct dsp_iir new = make_iir(5, 1);
|
|
||||||
double x = exp(-14.445*fcf);
|
|
||||||
|
|
||||||
new.ccof[0] = pow((1 - x), 4);
|
|
||||||
|
|
||||||
new.dcof[0] = 0.f;
|
|
||||||
new.dcof[1] = 4*x;
|
|
||||||
new.dcof[2] = -6 * pow(x, 2);
|
|
||||||
new.dcof[3] = 4 * pow(x, 3);
|
|
||||||
new.dcof[4] = -1 * pow(x,4);
|
|
||||||
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Biquad filters */
|
/* Biquad filters */
|
||||||
|
|
||||||
|
struct dsp_iir biquad_iir()
|
||||||
|
{
|
||||||
|
struct dsp_iir new;
|
||||||
|
new.dcof = malloc(sizeof(float) * 3);
|
||||||
|
new.ccof = malloc(sizeof(float) * 3);
|
||||||
|
new.dx = malloc(sizeof(float) * 3);
|
||||||
|
new.dy = malloc(sizeof(float) * 3);
|
||||||
|
new.n = 3;
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
void biquad_iir_fill(struct dsp_iir bq, double *a, double *b)
|
void biquad_iir_fill(struct dsp_iir bq, double *a, double *b)
|
||||||
{
|
{
|
||||||
bq.ccof[0] = (b[0] / a[0]);
|
bq.ccof[0] = (b[0] / a[0]);
|
||||||
|
@ -951,7 +842,7 @@ void p2_ccalc(double fcf, double p, double g, double *a, double *b)
|
||||||
double w0 = tan(M_PI * fcf);
|
double w0 = tan(M_PI * fcf);
|
||||||
double k[2];
|
double k[2];
|
||||||
k[0] = p * w0;
|
k[0] = p * w0;
|
||||||
k[1] = g * pow(w0, 2);
|
k[1] = g * pow2(w0);
|
||||||
|
|
||||||
a[0] = k[1] / (1 + k[0] + k[1]);
|
a[0] = k[1] / (1 + k[0] + k[1]);
|
||||||
a[1] = 2 * a[0];
|
a[1] = 2 * a[0];
|
||||||
|
@ -1021,7 +912,19 @@ struct dsp_iir p2_beshp(double fcf)
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct dsp_iir p2_iir_order(int order)
|
||||||
|
{
|
||||||
|
struct dsp_iir new;
|
||||||
|
new.n = 3;
|
||||||
|
new.order = order;
|
||||||
|
|
||||||
|
new.ccof = calloc(sizeof(float), 3 * order);
|
||||||
|
new.dcof = calloc(sizeof(float), 3 * order);
|
||||||
|
new.dx = calloc(sizeof(float), 3 * order);
|
||||||
|
new.dy = calloc(sizeof(float), 3 * order);
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
short p2_filter(struct dsp_iir iir, short val)
|
short p2_filter(struct dsp_iir iir, short val)
|
||||||
{
|
{
|
||||||
|
@ -1059,8 +962,8 @@ struct dsp_iir che_lp(int order, double fcf, double e)
|
||||||
|
|
||||||
|
|
||||||
double a = tan(M_PI * fcf);
|
double a = tan(M_PI * fcf);
|
||||||
double a2 = pow(a, 2);
|
double a2 = pow2(a);
|
||||||
double u = log((1.f + sqrt(1.f + pow(e, 2)))/e);
|
double u = log((1.f + sqrt(1.f + pow2(e)))/e);
|
||||||
double su = sinh(u/new.order);
|
double su = sinh(u/new.order);
|
||||||
double cu = cosh(u/new.order);
|
double cu = cosh(u/new.order);
|
||||||
double b, c, s;
|
double b, c, s;
|
||||||
|
@ -1070,7 +973,7 @@ struct dsp_iir che_lp(int order, double fcf, double e)
|
||||||
{
|
{
|
||||||
b = sin(M_PI * (2.f*i + 1.f)/(2.f*new.order)) * su;
|
b = sin(M_PI * (2.f*i + 1.f)/(2.f*new.order)) * su;
|
||||||
c = cos(M_PI * (2.f*i + 1.f)/(2.f*new.order)) * cu;
|
c = cos(M_PI * (2.f*i + 1.f)/(2.f*new.order)) * cu;
|
||||||
c = pow(b, 2) + pow(c, 2);
|
c = pow2(b) + pow2(c);
|
||||||
s = a2*c + 2.f*a*b + 1.f;
|
s = a2*c + 2.f*a*b + 1.f;
|
||||||
double A = a2/(4.f);
|
double A = a2/(4.f);
|
||||||
|
|
||||||
|
@ -1091,8 +994,8 @@ struct dsp_iir che_hp(int order, double fcf, double e)
|
||||||
struct dsp_iir new = che_lp(order, fcf, e);
|
struct dsp_iir new = che_lp(order, fcf, e);
|
||||||
|
|
||||||
double a = tan(M_PI * fcf);
|
double a = tan(M_PI * fcf);
|
||||||
double a2 = pow(a, 2);
|
double a2 = pow2(a);
|
||||||
double u = log((1.f + sqrt(1.f + pow(e, 2)))/e);
|
double u = log((1.f + sqrt(1.f + pow2(e)))/e);
|
||||||
double su = sinh(u/new.order);
|
double su = sinh(u/new.order);
|
||||||
double cu = cosh(u/new.order);
|
double cu = cosh(u/new.order);
|
||||||
double b, c, s;
|
double b, c, s;
|
||||||
|
@ -1102,7 +1005,7 @@ struct dsp_iir che_hp(int order, double fcf, double e)
|
||||||
{
|
{
|
||||||
b = sin(M_PI * (2.f*i + 1.f)/(2.f*new.order)) * su;
|
b = sin(M_PI * (2.f*i + 1.f)/(2.f*new.order)) * su;
|
||||||
c = cos(M_PI * (2.f*i + 1.f)/(2.f*new.order)) * cu;
|
c = cos(M_PI * (2.f*i + 1.f)/(2.f*new.order)) * cu;
|
||||||
c = pow(b, 2) + pow(c, 2);
|
c = pow2(b) + pow2(c);
|
||||||
s = a2*c + 2.f*a*b + 1.f;
|
s = a2*c + 2.f*a*b + 1.f;
|
||||||
double A = 1.f/(4.f);
|
double A = 1.f/(4.f);
|
||||||
|
|
||||||
|
@ -1118,23 +1021,29 @@ struct dsp_iir che_hp(int order, double fcf, double e)
|
||||||
|
|
||||||
struct dsp_iir che_bp(int order, double s, double fcf1, double fcf2, double e)
|
struct dsp_iir che_bp(int order, double s, double fcf1, double fcf2, double e)
|
||||||
{
|
{
|
||||||
struct dsp_iir new = make_iir(5, order);
|
if (order %4 != 0) {
|
||||||
|
YughWarn("Tried to make a filter with wrong order. Given order was %d, but order should be 4, 8, 12, ...", order);
|
||||||
|
}
|
||||||
|
|
||||||
double a = cos(M_PI*(fcf1+fcf2)/s) / cos(M_PI*(fcf2-fcf1)/s);
|
double ep = 2.f/e;
|
||||||
double a2 = pow(a, 2);
|
|
||||||
|
int n = order / 4;
|
||||||
|
struct dsp_iir new = p2_iir_order(order);
|
||||||
|
|
||||||
|
double a = cos(M_PI*(fcf1+fcf2)/2) / cos(M_PI*(fcf2-fcf1)/s);
|
||||||
|
double a2 = pow2(a);
|
||||||
double b = tan(M_PI*(fcf2-fcf1)/s);
|
double b = tan(M_PI*(fcf2-fcf1)/s);
|
||||||
double b2 = pow(b, 2);
|
double b2 = pow2(b);
|
||||||
double u = log((1.f+sqrt(1.f+pow(e, 2)))/e);
|
double u = log((1.f+sqrt(1.f+pow2(e)))/e);
|
||||||
double su = sinh(2.f*u/new.order);
|
double su = sinh(2.f*u/new.order);
|
||||||
double cu = cosh(2.f*u/new.order);
|
double cu = cosh(2.f*u/new.order);
|
||||||
double A = b2/(4.f);
|
double A = b2/(4.f);
|
||||||
double r, c;
|
double r, c;
|
||||||
double ep = 2.f/e;
|
|
||||||
|
|
||||||
for (int i = 0; i < new.order; ++i) {
|
for (int i = 0; i < new.order; ++i) {
|
||||||
r = sin(M_PI*(2.f*i+1.f)/new.order)*su;
|
r = sin(M_PI*(2.f*i+1.f)/new.order)*su;
|
||||||
c = cos(M_PI*(2.f*i+1.f)/new.order)*su;
|
c = cos(M_PI*(2.f*i+1.f)/new.order)*su;
|
||||||
c = pow(r, 2) + pow(c, 2);
|
c = pow2(r) + pow2(c);
|
||||||
s = b2*c + 2.f*b*r + 1.f;
|
s = b2*c + 2.f*b*r + 1.f;
|
||||||
|
|
||||||
new.ccof[0*i] = ep * 1.f/A;
|
new.ccof[0*i] = ep * 1.f/A;
|
||||||
|
@ -1151,32 +1060,37 @@ struct dsp_iir che_bp(int order, double s, double fcf1, double fcf2, double e)
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dsp_iir che_notch(int order, double s, double fcf1, double fcf2, double e)
|
struct dsp_iir che_notch(int order, double fcf1, double fcf2, double e)
|
||||||
{
|
{
|
||||||
struct dsp_iir new = make_iir(5, order);
|
if (order %4 != 0) {
|
||||||
|
YughWarn("Tried to make a filter with wrong order. Given order was %d, but order should be 4, 8, 12, ...", order);
|
||||||
|
}
|
||||||
|
|
||||||
double a = cos(M_PI*(fcf1+fcf2)/s) / cos(M_PI*(fcf2-fcf1)/s);
|
int n = order / 4;
|
||||||
double a2 = pow(a, 2);
|
|
||||||
|
struct dsp_iir new = p2_iir_order(order);
|
||||||
|
|
||||||
|
double a = cos(M_PI*(fcf1+fcf2)/2) / cos(M_PI*(fcf2-fcf1)/s);
|
||||||
|
double a2 = pow2(a);
|
||||||
double b = tan(M_PI*(fcf2-fcf1)/s);
|
double b = tan(M_PI*(fcf2-fcf1)/s);
|
||||||
double b2 = pow(b, 2);
|
double b2 = pow2(b);
|
||||||
double u = log((1.f+sqrt(1.f+pow(e, 2)))/e);
|
double u = log((1.f+sqrt(1.f+pow2(e)))/e);
|
||||||
double su = sinh(2.f*u/new.n);
|
double su = sinh(2.f*u/n);
|
||||||
double cu = cosh(2.f*u/new.n);
|
double cu = cosh(2.f*u/n);
|
||||||
double A = b2/(4.f*s);
|
double A = b2/(4.f*s);
|
||||||
double r, c;
|
double r, c, s;
|
||||||
double ep = 2.f/e;
|
|
||||||
|
|
||||||
for (int i = 0; i < new.order; ++i) {
|
for (int i = 0; i < new.order; ++i) {
|
||||||
r = sin(M_PI*(2.f*i+1.f)/new.order)*su;
|
r = sin(M_PI*(2.f*i+1.f)/new.order)*su;
|
||||||
c = cos(M_PI*(2.f*i+1.f)/new.order)*su;
|
c = cos(M_PI*(2.f*i+1.f)/ew.order)*su;
|
||||||
c = pow(r, 2) + pow(c, 2);
|
c = pow2(r) + pow2(c);
|
||||||
s = b2*c + 2.f*b*r + 1.f;
|
s = b2*c + 2.f*b*r + 1.f;
|
||||||
|
|
||||||
new.ccof[0*i] = ep * 1.f/A;
|
new.ccof[0*i] = ep * 1.f/A;
|
||||||
new.ccof[1*i] = ep * -2.f/A;
|
new.ccof[1*i] = ep * -2.f/A;
|
||||||
new.ccof[2*i] = ep * 1.f/A;
|
new.ccof[2*i] = ep * 1.f/A;
|
||||||
|
|
||||||
new.dcof[0*i] = 0.f;
|
new.ddof[0*i] = 0.f;
|
||||||
new.dcof[1*i] = ep * 4.f*a*(c+b*r)/s;
|
new.dcof[1*i] = ep * 4.f*a*(c+b*r)/s;
|
||||||
new.dcof[2*i] = ep * 2.f*(b2-2.f*a2*c-c)/s;
|
new.dcof[2*i] = ep * 2.f*(b2-2.f*a2*c-c)/s;
|
||||||
new.dcof[3*i] = ep * 4.f*a*(c-b*r)/s;
|
new.dcof[3*i] = ep * 4.f*a*(c-b*r)/s;
|
||||||
|
|
67
source/engine/music.c
Normal file
67
source/engine/music.c
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#include "music.h"
|
||||||
|
|
||||||
|
#include "dsp.h"
|
||||||
|
#include "tsf.h"
|
||||||
|
#include "tml.h"
|
||||||
|
#include "mix.h"
|
||||||
|
#include "sound.h"
|
||||||
|
|
||||||
|
#define TSF_BLOCK 64
|
||||||
|
|
||||||
|
struct dsp_filter cursong;
|
||||||
|
struct dsp_midi_song gsong;
|
||||||
|
|
||||||
|
void dsp_midi_fillbuf(struct dsp_midi_song *song, void *out, int n)
|
||||||
|
{
|
||||||
|
short *o = (short*)out;
|
||||||
|
tml_message *midi = song->midi;
|
||||||
|
|
||||||
|
for (int i = TSF_BLOCK; n; n -= i, o += n*CHANNELS) {
|
||||||
|
if (i > n) i = n;
|
||||||
|
|
||||||
|
for (song->time += i * (1000.f / SAMPLERATE); midi && song->time >= midi->time; midi = midi->next) {
|
||||||
|
switch (midi->type)
|
||||||
|
{
|
||||||
|
case TML_PROGRAM_CHANGE:
|
||||||
|
tsf_channel_set_presetnumber(song->sf, midi->channel, midi->program, (midi->channel == 9));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TML_NOTE_ON:
|
||||||
|
tsf_channel_note_on(song->sf, midi->channel, midi->key, midi->velocity / 127.f);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TML_NOTE_OFF:
|
||||||
|
tsf_channel_note_off(song->sf, midi->channel, midi->key);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TML_PITCH_BEND:
|
||||||
|
tsf_channel_set_pitchwheel(song->sf, midi->channel, midi->pitch_bend);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TML_CONTROL_CHANGE:
|
||||||
|
tsf_channel_midi_control(song->sf, midi->channel, midi->control, midi->control_value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tsf_render_short(song->sf, o, i, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
song->midi = midi;
|
||||||
|
}
|
||||||
|
|
||||||
|
void play_song(const char *midi, const char *sf)
|
||||||
|
{
|
||||||
|
gsong.midi = tml_load_filename("sounds/one-winged-angel.mid");
|
||||||
|
gsong.sf = tsf_load_filename("sounds/mario.sf2");
|
||||||
|
gsong.time = 0.f;
|
||||||
|
|
||||||
|
tsf_set_output(gsong.sf, TSF_STEREO_INTERLEAVED, SAMPLERATE, 0.f);
|
||||||
|
|
||||||
|
// Preset on 10th MIDI channel to use percussion sound bank if possible
|
||||||
|
tsf_channel_set_bank_preset(gsong.sf, 9, 128, 0);
|
||||||
|
|
||||||
|
cursong.data = &gsong;
|
||||||
|
cursong.filter = dsp_midi_fillbuf;
|
||||||
|
first_free_bus(cursong);
|
||||||
|
}
|
17
source/engine/music.h
Normal file
17
source/engine/music.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef MUSIC_H
|
||||||
|
#define MUSIC_H
|
||||||
|
|
||||||
|
#include "tsf.h"
|
||||||
|
#include "tml.h"
|
||||||
|
|
||||||
|
struct dsp_midi_song {
|
||||||
|
float bpm;
|
||||||
|
double time;
|
||||||
|
tsf *sf;
|
||||||
|
tml_message *midi;
|
||||||
|
};
|
||||||
|
|
||||||
|
void play_song(const char *midi, const char *sf);
|
||||||
|
void dsp_midi_fillbuf(struct dsp_midi_song *song, void *out, int n);
|
||||||
|
|
||||||
|
#endif
|
|
@ -6,6 +6,7 @@
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
#include "limits.h"
|
#include "limits.h"
|
||||||
#include "time.h"
|
#include "time.h"
|
||||||
|
#include "music.h"
|
||||||
|
|
||||||
|
|
||||||
#include "SDL2/SDL.h"
|
#include "SDL2/SDL.h"
|
||||||
|
@ -226,8 +227,7 @@ void sound_init()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
tsf *tsf_load_filename("sounds/ff7.sf2");
|
play_song("", "");
|
||||||
tml_message *tml_load_filename("sounds/one_winged_angel.mid");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_open(const char *device)
|
void audio_open(const char *device)
|
||||||
|
|
Loading…
Reference in a new issue