Skip to content

Instantly share code, notes, and snippets.

@stylemistake
Last active August 29, 2015 14:02
Show Gist options
  • Save stylemistake/e54e42b65ce820367b7f to your computer and use it in GitHub Desktop.
Save stylemistake/e54e42b65ce820367b7f to your computer and use it in GitHub Desktop.
C Juke
#include <stdio.h>
#include <math.h>
/*
Quick compile:
gcc juke.c -Ofast -lm -o juke && ./juke > juke.wav
*/
#define pat(x,y) (x)[bar%(y)]
/*
IV V VI
---------------
C 0 12 24
C# 1 13 25
D 2 14 26
D# 3 15 27
E 4 16 28
F 5 17 29
F# 6 18 30
G 7 19 31
G# 8 20 32
A 9 21 33
A# 10 22 34
B 11 23 35
*/
// ----------------------------------------------------------
#define RATE 44100
#define BASE_NOTE 440
#define NN_LIMIT -127
#define NN -255
int signal_sqr( int t, int note, float vel ) {
if ( note <= NN_LIMIT ) return 0;
int freq = BASE_NOTE * pow( 2, (float)(note-9)/12 );
float sig = (float)t / RATE * freq;
return (sin( sig * M_PI * 2 ) > 0 ? 1 : -1) * vel;
}
int signal_saw( int t, int note, float vel ) {
if ( note <= NN_LIMIT ) return 0;
int freq = BASE_NOTE * pow( 2, (float)(note-9)/12 );
int sig = (float)t * 0x80 / RATE * freq;
return ( (sig & 0xFF) - 0x80 ) * vel/0x80;
}
int signal_sin( int t, int note, float vel ) {
if ( note <= NN_LIMIT ) return 0;
int freq = BASE_NOTE * pow( 2, (float)(note-9)/12 );
float sig = (float)t / RATE * freq;
return sin( sig * M_PI * 2 ) * vel;
}
int signal_noise( int t, float vel ) {
int sig = rand();
return ( (sig & 0xFF) - 0x80 ) * vel/0x80;
}
// ----------------------------------------------------------
int synth_tune( unsigned int t ) {
int melody[] = {
12, 17, 20, 19, NN, NN, NN, NN,
12, 7, 14, 15, NN, NN, NN, NN,
10, 14, 17, 22, NN, NN, NN, NN,
12, 15, 20, 24, NN, NN, NN, NN,
};
int melody_pitch[] = { 0, 1, 0, 2 };
int note = melody[ t>>13&31 ] + melody_pitch[ t>>18&3 ] * 12;
int vel = (-t)>>7&63;
return signal_saw( t, note, vel );
}
int synth_arp( unsigned int t ) {
int melody[] = {
12, 17, 20, 7, 12, 15,
10, 14, 17, 12, 15, 20,
};
int melody_pitch[] = { 0, 1, 0, 2 };
int note = melody[ (t>>11)%3 + 3*(t>>16&3) ];
int vel = (-t)>>7&63;
return signal_saw( t, note + 12, 12 );
}
int synth_bass( unsigned int t ) {
int melody[] = {
17, 12, 19, 20,
17, 12, 19, 18,
};
int note = melody[ t>>16&7 ] - 36;
int vel = sin( (float)t * 12 / RATE ) * 20;
return signal_sin( t, note, 35 ) + signal_sqr( t, note, vel );
}
int synth_kick( unsigned int t ) {
int pitches[] = {
30, 15, 7, 4, 0, 0, 0, 0,
};
int vel_map[] = {
0x50, 0x60, 0x80, 0x60, 0x50, 0x40, 0x35, 0x30,
};
int trigger_map[] = {
1, 0, 0, 0, 1, 0, 0, 0,
1, 0, 0, 1, 0, 0, 1, 0,
1, 0, 0, 0, 1, 0, 0, 0,
1, 0, 0, 1, 0, 0, 1, 1,
};
int note = pitches[ t>>9&7 ] - 24;
int vel = vel_map[ t>>9&7 ] * trigger_map[ t>>12&31 ] / 1.5;
return signal_sin( t, note, vel );
}
int synth_clap( unsigned int t ) {
int vel_map[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF0, 0x80, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00,
};
int vel = vel_map[ t>>12&15 ] / 5;
return signal_noise( t, vel );
}
int synth_beeps( unsigned int t ) {
int vel_map[] = {
0xF0, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF0, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF0, 0x00, 0xF0, 0x00,
};
int melody_pitch[] = { 0, -9 };
int note = 36 + melody_pitch[ t>>16&1 ];
int vel = vel_map[ t>>11&15 ] / 10;
return signal_sqr( t, note, vel );
}
int synth_closed_hat( unsigned int t ) {
int vel_map[] = {
0xF0, 0x80, 0x40, 0x20, 0x10, 0x05, 0x02, 0x01,
};
int vel = vel_map[ t>>9&7 ] / 4;
return signal_noise( t, vel );
}
int main() {
unsigned int t = 0;
int bar_mul = 18;
int bar_end = 20;
// Write RIFF header
int header[] = {
0x46464952, // RIFF
0x00000824, // ChunkSize
0x45564157, // WAVE
0x20746d66, // fmt_
0x00000010, // Subchunk1Size
0x00010001, // NumChannels + PCM
RATE, // SampleRate
RATE, // ByteRate
0x00080001, // Bits + BlockAlign
0x61746164, // DATA
( 1 << bar_mul ) * bar_end // Subchunk2Size
};
for ( t = 0; t < 12; t++ ) {
putchar( header[t] & 0xFF );
putchar( header[t] >> 8 & 0xFF );
putchar( header[t] >> 16 & 0xFF );
putchar( header[t] >> 24 & 0xFF );
}
for (;; t++) {
int sig = 0;
int bar = t >> 18;
// End of music
if ( bar == 20 ) break;
// Patterns
int pat_tune[] = { 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
int pat_bass[] = { 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, };
int pat_arp[] = { 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, };
int pat_beeps[] = { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, };
int pat_kick[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, };
int pat_clap[] = { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, };
int pat_chat[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, };
// Instruments
sig += pat( pat_tune, 20 ) * synth_tune(t);
sig += pat( pat_bass, 20 ) * synth_bass(t);
sig += pat( pat_arp, 20 ) * synth_arp(t);
sig += pat( pat_beeps,20 ) * synth_beeps(t);
sig += pat( pat_clap, 20 ) * synth_clap(t);
sig += pat( pat_kick, 20 ) * synth_kick(t);
sig += pat( pat_chat, 20 ) * synth_closed_hat(t);
// Dirty clipping
if ( sig >= 0x80 ) sig = 0x79;
else if ( sig <= -0x80 ) sig = -0x79;
// Output
putchar( (sig+0x80) & 0xFF );
}
// Zero padding
for ( t = 0; t < 256; t++ ) putchar(0);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment