|
|
|
|
@ -6,7 +6,7 @@
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
|
|
#define MAX_NOTES 26
|
|
|
|
|
#define MAX_NOTES 16
|
|
|
|
|
|
|
|
|
|
const int window_width = 640;
|
|
|
|
|
const int window_height = 480;
|
|
|
|
|
@ -34,7 +34,45 @@ typedef struct note {
|
|
|
|
|
bool released;
|
|
|
|
|
} note;
|
|
|
|
|
|
|
|
|
|
note scale[MAX_NOTES];
|
|
|
|
|
note scale[26];
|
|
|
|
|
|
|
|
|
|
typedef struct keymap {
|
|
|
|
|
int key;
|
|
|
|
|
int idx;
|
|
|
|
|
} keymap;
|
|
|
|
|
|
|
|
|
|
typedef struct note_stack {
|
|
|
|
|
int nsp; //stack pointer
|
|
|
|
|
note notes[MAX_NOTES];
|
|
|
|
|
keymap keys[MAX_NOTES];
|
|
|
|
|
} note_stack;
|
|
|
|
|
|
|
|
|
|
//so the stack can be accessed in the callback
|
|
|
|
|
note_stack *nsptr;
|
|
|
|
|
|
|
|
|
|
static inline void push_note(note_stack *ns, note n) {
|
|
|
|
|
ns->nsp = ns->nsp % MAX_NOTES;
|
|
|
|
|
//printf("%s: %d\n", "push_note", ns->nsp);
|
|
|
|
|
ns->notes[ns->nsp] = n;
|
|
|
|
|
ns->nsp++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//must come before push_note
|
|
|
|
|
static inline void push_key(note_stack *ns, int k) {
|
|
|
|
|
ns->keys[ns->nsp % MAX_NOTES].key = k;
|
|
|
|
|
ns->keys[ns->nsp % MAX_NOTES].idx = ns->nsp % MAX_NOTES; //might not need
|
|
|
|
|
//printf("%s: %d %d %d\n", "push_key", ns->nsp % MAX_NOTES, ns->keys[ns->nsp % MAX_NOTES].key, ns->keys[ns->nsp % MAX_NOTES].idx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void release_note(note_stack *ns, int k) {
|
|
|
|
|
for (int i = 0; i < MAX_NOTES; i++) {
|
|
|
|
|
if (ns->keys[i].key == k) {
|
|
|
|
|
//printf("%s %d %d\n", "release note", k, i);
|
|
|
|
|
ns->notes[i].released = true; //try i first
|
|
|
|
|
ns->keys[i].key = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float sine_wave(float idx) {
|
|
|
|
|
return sinf(2 * PI * idx);
|
|
|
|
|
@ -48,43 +86,61 @@ float square_wave(float idx) {
|
|
|
|
|
return -0.5f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline int count_active_notes(void) {
|
|
|
|
|
float saw_wave(float idx) {
|
|
|
|
|
return idx - 0.5f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float reverse_saw_wave(float idx) {
|
|
|
|
|
return -idx + 0.5f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float semisine_wave(float idx) {
|
|
|
|
|
return (idx * idx)/2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//not needed?
|
|
|
|
|
static inline int count_active_notes(note_stack *ns) {
|
|
|
|
|
int active = 0;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < MAX_NOTES; i++) {
|
|
|
|
|
if (scale[i].volume > 0.0f)
|
|
|
|
|
if (ns->notes[i].volume > 0.0f) {
|
|
|
|
|
//printf("%s %f\n", "wtf?:", ns->notes[i].volume);
|
|
|
|
|
active++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//printf("%s: %d\n", "active notes", active);
|
|
|
|
|
return active;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline float add_notes(void) {
|
|
|
|
|
//add each notes index
|
|
|
|
|
float m = 0;
|
|
|
|
|
int active = count_active_notes();
|
|
|
|
|
static inline float add_notes(note_stack *ns) {
|
|
|
|
|
float m = 0.0f;
|
|
|
|
|
//int active = count_active_notes(ns);
|
|
|
|
|
float compress = 0.0f;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < MAX_NOTES; i++) {
|
|
|
|
|
m += square_wave(scale[i].index) * scale[i].volume;
|
|
|
|
|
m += sine_wave(ns->notes[i].index) * ns->notes[i].volume;
|
|
|
|
|
m += square_wave(ns->notes[i].index) * ns->notes[i].volume;
|
|
|
|
|
compress += scale[i].volume;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//don't divide by zero
|
|
|
|
|
|
|
|
|
|
m = active ? m/active : 0.0f; //compression
|
|
|
|
|
//m = m + (1.0f - m) * 0.95f;
|
|
|
|
|
return m;
|
|
|
|
|
m = compress ? m/compress : 0.0f; //compression
|
|
|
|
|
|
|
|
|
|
//m = (m - (-1.0f*active)) / (1.0f*active) - (-1.0f*active);
|
|
|
|
|
return m * 5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline float calc_note_step(note *n) {
|
|
|
|
|
return n->frequency/sample_rate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void reset_index(void) {
|
|
|
|
|
static inline void reset_index(note_stack *ns) {
|
|
|
|
|
for (size_t i = 0; i < MAX_NOTES; i++) {
|
|
|
|
|
|
|
|
|
|
scale[i].index += scale[i].step;
|
|
|
|
|
if (scale[i].index > 1.0f && scale[i].volume > 0.0f) {
|
|
|
|
|
scale[i].index -= 1.0f;
|
|
|
|
|
ns->notes[i].index += ns->notes[i].step;
|
|
|
|
|
if (ns->notes[i].index > 1.0f && ns->notes[i].volume > 0.0f) {
|
|
|
|
|
ns->notes[i].index -= 1.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -94,26 +150,24 @@ void AudioInputCallback2(void *buffer, uint32_t frames) {
|
|
|
|
|
short *d = (short *)buffer;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < frames; i++) {
|
|
|
|
|
d[i] = (signed short)(pcm_volume * add_notes());;
|
|
|
|
|
reset_index();
|
|
|
|
|
d[i] = (signed short)(pcm_volume * add_notes(nsptr));
|
|
|
|
|
reset_index(nsptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const float volume_release_step = 0.01f;
|
|
|
|
|
|
|
|
|
|
void key_press(int key, note *n) {
|
|
|
|
|
void key_press(int key, note_stack *ns, note n) {
|
|
|
|
|
if (IsKeyPressed(key)) {
|
|
|
|
|
//keys_pressed++;
|
|
|
|
|
n->released = false;
|
|
|
|
|
push_key(ns, key);
|
|
|
|
|
push_note(ns, n);
|
|
|
|
|
//n->released = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsKeyReleased(key)) {
|
|
|
|
|
//keys_pressed--;
|
|
|
|
|
n->released = true;
|
|
|
|
|
//ns->notes[/*saved idx*/].released = true;
|
|
|
|
|
release_note(ns, key);
|
|
|
|
|
//n->released = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//printf("%s\n", "wow");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
|
@ -128,61 +182,78 @@ int main(int argc, char *argv[]) {
|
|
|
|
|
|
|
|
|
|
PlayAudioStream(stream);
|
|
|
|
|
|
|
|
|
|
const float volume_attack_step = 0.08f;
|
|
|
|
|
const float volume_release_step = 0.08f;
|
|
|
|
|
note_stack ns;
|
|
|
|
|
ns.nsp = 0;
|
|
|
|
|
|
|
|
|
|
//init scale
|
|
|
|
|
for (int i = 0; i < MAX_NOTES; i++) {
|
|
|
|
|
ns.notes[i] = (note){
|
|
|
|
|
.volume = 0.0f,
|
|
|
|
|
.released = true,
|
|
|
|
|
.index = 0.0f,
|
|
|
|
|
};
|
|
|
|
|
ns.keys[i] = (keymap){0};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsptr = &ns;
|
|
|
|
|
|
|
|
|
|
const float volume_attack_step = 0.04f;
|
|
|
|
|
const float volume_release_step = 0.04f;
|
|
|
|
|
|
|
|
|
|
//init scale
|
|
|
|
|
for (int i = 0; i < 26; i++) {
|
|
|
|
|
scale[i].frequency = semitone(i-24);
|
|
|
|
|
scale[i].index = 0.0f;
|
|
|
|
|
scale[i].volume = 0.0f;
|
|
|
|
|
scale[i].volume = 1.0f;
|
|
|
|
|
scale[i].step = calc_note_step(&scale[i]);
|
|
|
|
|
scale[i].released = true;
|
|
|
|
|
scale[i].released = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while(!WindowShouldClose()) {
|
|
|
|
|
key_press(KEY_Z, &scale[0]);
|
|
|
|
|
key_press(KEY_X, &scale[1]);
|
|
|
|
|
key_press(KEY_C, &scale[2]);
|
|
|
|
|
key_press(KEY_V, &scale[3]);
|
|
|
|
|
key_press(KEY_B, &scale[4]);
|
|
|
|
|
key_press(KEY_N, &scale[5]);
|
|
|
|
|
key_press(KEY_M, &scale[6]);
|
|
|
|
|
key_press(KEY_A, &scale[7]);
|
|
|
|
|
key_press(KEY_S, &scale[8]);
|
|
|
|
|
key_press(KEY_D, &scale[9]);
|
|
|
|
|
key_press(KEY_F, &scale[10]);
|
|
|
|
|
key_press(KEY_G, &scale[11]);
|
|
|
|
|
key_press(KEY_H, &scale[12]);
|
|
|
|
|
key_press(KEY_J, &scale[13]);
|
|
|
|
|
key_press(KEY_K, &scale[14]);
|
|
|
|
|
key_press(KEY_L, &scale[15]);
|
|
|
|
|
key_press(KEY_Q, &scale[16]);
|
|
|
|
|
key_press(KEY_W, &scale[17]);
|
|
|
|
|
key_press(KEY_E, &scale[18]);
|
|
|
|
|
key_press(KEY_R, &scale[19]);
|
|
|
|
|
key_press(KEY_T, &scale[20]);
|
|
|
|
|
key_press(KEY_Y, &scale[21]);
|
|
|
|
|
key_press(KEY_U, &scale[22]);
|
|
|
|
|
key_press(KEY_I, &scale[23]);
|
|
|
|
|
key_press(KEY_O, &scale[24]);
|
|
|
|
|
key_press(KEY_P, &scale[25]);
|
|
|
|
|
key_press(KEY_Z, &ns, scale[0]);
|
|
|
|
|
key_press(KEY_X, &ns, scale[1]);
|
|
|
|
|
key_press(KEY_C, &ns, scale[2]);
|
|
|
|
|
key_press(KEY_V, &ns, scale[3]);
|
|
|
|
|
key_press(KEY_B, &ns, scale[4]);
|
|
|
|
|
key_press(KEY_N, &ns, scale[5]);
|
|
|
|
|
key_press(KEY_M, &ns, scale[6]);
|
|
|
|
|
key_press(KEY_A, &ns, scale[7]);
|
|
|
|
|
key_press(KEY_S, &ns, scale[8]);
|
|
|
|
|
key_press(KEY_D, &ns, scale[9]);
|
|
|
|
|
key_press(KEY_F, &ns, scale[10]);
|
|
|
|
|
key_press(KEY_G, &ns, scale[11]);
|
|
|
|
|
key_press(KEY_H, &ns, scale[12]);
|
|
|
|
|
key_press(KEY_J, &ns, scale[13]);
|
|
|
|
|
key_press(KEY_K, &ns, scale[14]);
|
|
|
|
|
key_press(KEY_L, &ns, scale[15]);
|
|
|
|
|
key_press(KEY_Q, &ns, scale[16]);
|
|
|
|
|
key_press(KEY_W, &ns, scale[17]);
|
|
|
|
|
key_press(KEY_E, &ns, scale[18]);
|
|
|
|
|
key_press(KEY_R, &ns, scale[19]);
|
|
|
|
|
key_press(KEY_T, &ns, scale[20]);
|
|
|
|
|
key_press(KEY_Y, &ns, scale[21]);
|
|
|
|
|
key_press(KEY_U, &ns, scale[22]);
|
|
|
|
|
key_press(KEY_I, &ns, scale[23]);
|
|
|
|
|
key_press(KEY_O, &ns, scale[24]);
|
|
|
|
|
key_press(KEY_P, &ns, scale[25]);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < MAX_NOTES; i++) {
|
|
|
|
|
if (scale[i].released) {
|
|
|
|
|
scale[i].volume -= volume_release_step;
|
|
|
|
|
if (scale[i].volume < 0.0f) {
|
|
|
|
|
scale[i].volume = 0.0f;
|
|
|
|
|
scale[i].index = 0.0f;
|
|
|
|
|
if (ns.notes[i].released) {
|
|
|
|
|
//printf("lowering volume: %f\n", ns.notes[i].volume);
|
|
|
|
|
ns.notes[i].volume -= volume_release_step;
|
|
|
|
|
//printf("lowering volume: %f\n", ns.notes[i].volume);
|
|
|
|
|
if (ns.notes[i].volume < 0.0f) {
|
|
|
|
|
ns.notes[i].volume = 0.0f;
|
|
|
|
|
ns.notes[i].index = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < MAX_NOTES; i++) {
|
|
|
|
|
if (!scale[i].released) {
|
|
|
|
|
scale[i].volume += volume_attack_step;
|
|
|
|
|
if (scale[i].volume > 1.0f) {
|
|
|
|
|
scale[i].volume = 1.0f;
|
|
|
|
|
if (!ns.notes[i].released) {
|
|
|
|
|
//printf("%s\n", "bugs?");
|
|
|
|
|
ns.notes[i].volume += volume_attack_step;
|
|
|
|
|
if (ns.notes[i].volume > 1.0f) {
|
|
|
|
|
ns.notes[i].volume = 1.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|