sound
commit
47349d3bf7
@ -0,0 +1,26 @@
|
|||||||
|
SHELL=/bin/sh
|
||||||
|
CC=gcc
|
||||||
|
|
||||||
|
APP_NAME=synthesizer
|
||||||
|
|
||||||
|
SRC=src
|
||||||
|
BUILD=build
|
||||||
|
|
||||||
|
C_FILES := $(shell find $(SRC) -name '*.c')
|
||||||
|
O_FILES += $(patsubst $(SRC)/%.c, $(BUILD)/%.o, $(C_FILES))
|
||||||
|
|
||||||
|
CFLAGS := -O0 -march=native -std=gnu99
|
||||||
|
INCLUDE :=
|
||||||
|
LIB := -lm -lraylib
|
||||||
|
|
||||||
|
|
||||||
|
synthesizer: $(APP_NAME)
|
||||||
|
|
||||||
|
$(APP_NAME): $(O_FILES)
|
||||||
|
$(CC) $(CFLAGS) $(O_FILES) -o $(APP_NAME) $(LIB)
|
||||||
|
|
||||||
|
$(BUILD)/%.o: $(SRC)/%.c
|
||||||
|
$(CC) $(INCLUDE) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm $(BUILD)/*.o
|
||||||
@ -0,0 +1,201 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <raylib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define MAX_NOTES 26
|
||||||
|
|
||||||
|
const int window_width = 640;
|
||||||
|
const int window_height = 480;
|
||||||
|
char *window_title = "synthesizer";
|
||||||
|
|
||||||
|
//44100 samples per second
|
||||||
|
const int sample_rate = 44100;
|
||||||
|
float duration = 1.0f;
|
||||||
|
float pcm_volume = 10000.0f;
|
||||||
|
const float pitch_standard = 440.0; //A440
|
||||||
|
int active_notes = 0;
|
||||||
|
|
||||||
|
//convert semitone starting from pitch_standard to frequency
|
||||||
|
float semitone(float semitone) {
|
||||||
|
float a = powf(2.0f, (1.0f/12.0f));
|
||||||
|
float n = pitch_standard * powf(a, semitone);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct note {
|
||||||
|
float frequency;
|
||||||
|
float index;
|
||||||
|
float step;
|
||||||
|
float volume;
|
||||||
|
bool released;
|
||||||
|
} note;
|
||||||
|
|
||||||
|
note scale[MAX_NOTES];
|
||||||
|
|
||||||
|
float sine_wave(float idx) {
|
||||||
|
return sinf(2 * PI * idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
float square_wave(float idx) {
|
||||||
|
if ( sine_wave(idx) > 0.0f )
|
||||||
|
return 0.5f;
|
||||||
|
|
||||||
|
if ( sine_wave(idx) < 0.0f )
|
||||||
|
return -0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int count_active_notes(void) {
|
||||||
|
int active = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < MAX_NOTES; i++) {
|
||||||
|
if (scale[i].volume > 0.0f)
|
||||||
|
active++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float add_notes(void) {
|
||||||
|
//add each notes index
|
||||||
|
float m = 0;
|
||||||
|
int active = count_active_notes();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < MAX_NOTES; i++) {
|
||||||
|
m += square_wave(scale[i].index) * scale[i].volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
//don't divide by zero
|
||||||
|
|
||||||
|
m = active ? m/active : 0.0f; //compression
|
||||||
|
//m = m + (1.0f - m) * 0.95f;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float calc_note_step(note *n) {
|
||||||
|
return n->frequency/sample_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void reset_index(void) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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++) {
|
||||||
|
d[i] = (signed short)(pcm_volume * add_notes());;
|
||||||
|
reset_index();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const float volume_release_step = 0.01f;
|
||||||
|
|
||||||
|
void key_press(int key, note *n) {
|
||||||
|
if (IsKeyPressed(key)) {
|
||||||
|
//keys_pressed++;
|
||||||
|
n->released = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsKeyReleased(key)) {
|
||||||
|
//keys_pressed--;
|
||||||
|
n->released = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("%s\n", "wow");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
InitWindow(window_width, window_height, window_title);
|
||||||
|
SetTargetFPS(60);
|
||||||
|
|
||||||
|
InitAudioDevice();
|
||||||
|
SetAudioStreamBufferSizeDefault(4096);
|
||||||
|
|
||||||
|
AudioStream stream = LoadAudioStream(44100, 16, 1);
|
||||||
|
SetAudioStreamCallback(stream, AudioInputCallback2);
|
||||||
|
|
||||||
|
PlayAudioStream(stream);
|
||||||
|
|
||||||
|
const float volume_attack_step = 0.08f;
|
||||||
|
const float volume_release_step = 0.08f;
|
||||||
|
|
||||||
|
//init scale
|
||||||
|
for (int i = 0; i < MAX_NOTES; i++) {
|
||||||
|
scale[i].frequency = semitone(i-24);
|
||||||
|
scale[i].index = 0.0f;
|
||||||
|
scale[i].volume = 0.0f;
|
||||||
|
scale[i].step = calc_note_step(&scale[i]);
|
||||||
|
scale[i].released = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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]);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ClearBackground(BLACK);
|
||||||
|
|
||||||
|
BeginDrawing();
|
||||||
|
|
||||||
|
EndDrawing();
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseWindow();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in New Issue