|
|
|
|
@ -16,8 +16,10 @@ char *window_title = "synthesizer";
|
|
|
|
|
const int sample_rate = 44100;
|
|
|
|
|
float duration = 1.0f;
|
|
|
|
|
float pcm_volume = 10000.0f;
|
|
|
|
|
const float pitch_standard = 440.0; //A440
|
|
|
|
|
const float pitch_standard = 480.0; //A440
|
|
|
|
|
int active_notes = 0;
|
|
|
|
|
float freqmod = 0.5f; //for pitch bending
|
|
|
|
|
Color visual;
|
|
|
|
|
|
|
|
|
|
//convert semitone starting from pitch_standard to frequency
|
|
|
|
|
float semitone(float semitone) {
|
|
|
|
|
@ -34,7 +36,7 @@ typedef struct note {
|
|
|
|
|
bool released;
|
|
|
|
|
} note;
|
|
|
|
|
|
|
|
|
|
note scale[26];
|
|
|
|
|
note scale[36];
|
|
|
|
|
|
|
|
|
|
typedef struct keymap {
|
|
|
|
|
int key;
|
|
|
|
|
@ -50,25 +52,45 @@ typedef struct note_stack {
|
|
|
|
|
//so the stack can be accessed in the callback
|
|
|
|
|
note_stack *nsptr;
|
|
|
|
|
|
|
|
|
|
static inline void push_note(note_stack *ns, note n) {
|
|
|
|
|
static inline void set_visual_color(void) {
|
|
|
|
|
visual.r = rand();
|
|
|
|
|
visual.g = rand();
|
|
|
|
|
visual.b = rand();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void darken_visual(void) {
|
|
|
|
|
if (visual.r) {
|
|
|
|
|
visual.r--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (visual.g) {
|
|
|
|
|
visual.g--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (visual.b) {
|
|
|
|
|
visual.b--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void push_note(note_stack *ns, note n, int key) {
|
|
|
|
|
ns->keys[ns->nsp % MAX_NOTES].key = key;
|
|
|
|
|
ns->keys[ns->nsp % MAX_NOTES].idx = ns->nsp % MAX_NOTES; //might not need
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
//must come before push_note, probably dont need
|
|
|
|
|
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->notes[i].released = true;
|
|
|
|
|
ns->keys[i].key = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -104,18 +126,15 @@ static inline int count_active_notes(note_stack *ns) {
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < MAX_NOTES; i++) {
|
|
|
|
|
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(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++) {
|
|
|
|
|
@ -138,7 +157,7 @@ static inline float calc_note_step(note *n) {
|
|
|
|
|
static inline void reset_index(note_stack *ns) {
|
|
|
|
|
for (size_t i = 0; i < MAX_NOTES; i++) {
|
|
|
|
|
|
|
|
|
|
ns->notes[i].index += ns->notes[i].step;
|
|
|
|
|
ns->notes[i].index += ns->notes[i].step * freqmod * 2;
|
|
|
|
|
if (ns->notes[i].index > 1.0f && ns->notes[i].volume > 0.0f) {
|
|
|
|
|
ns->notes[i].index -= 1.0f;
|
|
|
|
|
}
|
|
|
|
|
@ -146,7 +165,6 @@ static inline void reset_index(note_stack *ns) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AudioInputCallback2(void *buffer, uint32_t frames) {
|
|
|
|
|
//audio_frequency = frequency + (audio_frequency - frequency) * 0.95f;
|
|
|
|
|
short *d = (short *)buffer;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < frames; i++) {
|
|
|
|
|
@ -158,18 +176,21 @@ void AudioInputCallback2(void *buffer, uint32_t frames) {
|
|
|
|
|
|
|
|
|
|
void key_press(int key, note_stack *ns, note n) {
|
|
|
|
|
if (IsKeyPressed(key)) {
|
|
|
|
|
push_key(ns, key);
|
|
|
|
|
push_note(ns, n);
|
|
|
|
|
//n->released = false;
|
|
|
|
|
set_visual_color();
|
|
|
|
|
push_note(ns, n, key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsKeyReleased(key)) {
|
|
|
|
|
//ns->notes[/*saved idx*/].released = true;
|
|
|
|
|
release_note(ns, key);
|
|
|
|
|
//n->released = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct penger {
|
|
|
|
|
Vector2 position;
|
|
|
|
|
Vector2 velocity;
|
|
|
|
|
Texture2D texture;
|
|
|
|
|
} penger;
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
|
InitWindow(window_width, window_height, window_title);
|
|
|
|
|
SetTargetFPS(60);
|
|
|
|
|
@ -180,6 +201,16 @@ int main(int argc, char *argv[]) {
|
|
|
|
|
AudioStream stream = LoadAudioStream(44100, 16, 1);
|
|
|
|
|
SetAudioStreamCallback(stream, AudioInputCallback2);
|
|
|
|
|
|
|
|
|
|
Image penger_image = LoadImage("penger.png");
|
|
|
|
|
Texture2D penger_texture = LoadTextureFromImage(penger_image);
|
|
|
|
|
UnloadImage(penger_image);
|
|
|
|
|
|
|
|
|
|
//init penger
|
|
|
|
|
penger penger;
|
|
|
|
|
penger.position = (Vector2){window_width/2, window_height/2};
|
|
|
|
|
penger.velocity = (Vector2){0, 0};
|
|
|
|
|
penger.texture = penger_texture;
|
|
|
|
|
|
|
|
|
|
PlayAudioStream(stream);
|
|
|
|
|
|
|
|
|
|
note_stack ns;
|
|
|
|
|
@ -200,8 +231,8 @@ int main(int argc, char *argv[]) {
|
|
|
|
|
const float volume_release_step = 0.04f;
|
|
|
|
|
|
|
|
|
|
//init scale
|
|
|
|
|
for (int i = 0; i < 26; i++) {
|
|
|
|
|
scale[i].frequency = semitone(i-24);
|
|
|
|
|
for (int i = 0; i < 36; i++) {
|
|
|
|
|
scale[i].frequency = semitone(i-36);
|
|
|
|
|
scale[i].index = 0.0f;
|
|
|
|
|
scale[i].volume = 1.0f;
|
|
|
|
|
scale[i].step = calc_note_step(&scale[i]);
|
|
|
|
|
@ -236,11 +267,22 @@ int main(int argc, char *argv[]) {
|
|
|
|
|
key_press(KEY_O, &ns, scale[24]);
|
|
|
|
|
key_press(KEY_P, &ns, scale[25]);
|
|
|
|
|
|
|
|
|
|
key_press(KEY_ONE, &ns, scale[26]);
|
|
|
|
|
key_press(KEY_TWO, &ns, scale[27]);
|
|
|
|
|
key_press(KEY_THREE, &ns, scale[28]);
|
|
|
|
|
key_press(KEY_FOUR, &ns, scale[29]);
|
|
|
|
|
key_press(KEY_FIVE, &ns, scale[30]);
|
|
|
|
|
key_press(KEY_SIX, &ns, scale[31]);
|
|
|
|
|
key_press(KEY_SEVEN, &ns, scale[32]);
|
|
|
|
|
key_press(KEY_EIGHT, &ns, scale[33]);
|
|
|
|
|
key_press(KEY_NINE, &ns, scale[34]);
|
|
|
|
|
key_press(KEY_ZERO, &ns, scale[35]);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < MAX_NOTES; i++) {
|
|
|
|
|
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;
|
|
|
|
|
@ -250,7 +292,6 @@ int main(int argc, char *argv[]) {
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < MAX_NOTES; i++) {
|
|
|
|
|
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;
|
|
|
|
|
@ -258,11 +299,51 @@ int main(int argc, char *argv[]) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
|
|
|
|
|
freqmod = -GetMouseY()/1000.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) {
|
|
|
|
|
freqmod = 1.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ClearBackground(visual);
|
|
|
|
|
|
|
|
|
|
ClearBackground(BLACK);
|
|
|
|
|
darken_visual();
|
|
|
|
|
|
|
|
|
|
BeginDrawing();
|
|
|
|
|
|
|
|
|
|
DrawTextureEx(penger.texture, penger.position, 0.0f, 0.125f, WHITE);
|
|
|
|
|
penger.velocity.x = (rand() % (2 - -2 + 2)) + 0;
|
|
|
|
|
penger.velocity.y = (rand() % (2 - -2 + 2)) + 0;
|
|
|
|
|
|
|
|
|
|
penger.velocity.x += -(rand() % (2 - -2 + 2)) + 0;
|
|
|
|
|
penger.velocity.y += -(rand() % (2 - -2 + 2)) + 0;
|
|
|
|
|
|
|
|
|
|
penger.position.x += penger.velocity.x;
|
|
|
|
|
penger.position.y += penger.velocity.y;
|
|
|
|
|
|
|
|
|
|
if (penger.position.x > window_width) {
|
|
|
|
|
//penger.position.x = window_width/2;
|
|
|
|
|
penger.velocity.x = -penger.velocity.x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (penger.position.x < 0) {
|
|
|
|
|
//penger.position.x = 0;
|
|
|
|
|
penger.velocity.x = -penger.velocity.x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (penger.position.y > window_height) {
|
|
|
|
|
//penger.position.y = window_height/2;
|
|
|
|
|
penger.velocity.y = -penger.velocity.y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (penger.position.y < 0) {
|
|
|
|
|
//penger.position.y = 0;
|
|
|
|
|
penger.velocity.y = -penger.velocity.y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EndDrawing();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|