diff --git a/audio.c b/audio.c new file mode 100644 index 0000000..5001dd8 --- /dev/null +++ b/audio.c @@ -0,0 +1,130 @@ +#include "audio.h" +#include "log.h" + +const int MAX_RECORDING_SECONDS = 1; + +static SDL_AudioSpec recording_spec; +static SDL_AudioSpec playback_spec; +static SDL_AudioSpec received_recording_spec; +static SDL_AudioSpec received_playback_spec; + +int audio_init(audio_state* state) +{ + state->recording_device_id = 0; + state->playback_device_id = 0; + + SDL_zero(recording_spec); + recording_spec.freq = 44100; + recording_spec.format = AUDIO_S16; + recording_spec.channels = 2; + recording_spec.samples = 4096; + recording_spec.callback = audio_recording_callback; + recording_spec.userdata = state; + + SDL_zero(playback_spec); + playback_spec.freq = 44100; + playback_spec.format = AUDIO_S16; + playback_spec.channels = 2; + playback_spec.samples = 4096; + playback_spec.callback = audio_playback_callback; + playback_spec.userdata = state; + + state->recording_buffer = NULL; + state->recording_buffer_size = 0; + state->recording_buffer_position = 0; + + return 1; +} + +int audio_recording_init(audio_state* state, int index) +{ + SDL_AudioDeviceID device_id = SDL_OpenAudioDevice(SDL_GetAudioDeviceName(index, 1), 1, &recording_spec, &received_recording_spec, SDL_AUDIO_ALLOW_FORMAT_CHANGE); + printf("Recording Device: %s\n", SDL_GetAudioDeviceName(index, 1)); + if (!device_id) { + printf("Failed to open recording device! SDL Error: %s", SDL_GetError()); + return 0; + } + state->recording_device_id = device_id; + + unsigned int bytes_per_sample = received_recording_spec.channels * (SDL_AUDIO_BITSIZE(received_recording_spec.format)/8); + unsigned int bytes_per_second = received_recording_spec.freq * bytes_per_sample; + state->recording_buffer_size = MAX_RECORDING_SECONDS * bytes_per_second; + + if (state->recording_buffer) free(state->recording_buffer); + state->recording_buffer = malloc(state->recording_buffer_size); + memset(state->recording_buffer, 0, state->recording_buffer_size); + + return 1; +} + +void audio_destroy(audio_state* state) +{ + free(state->recording_buffer); + SDL_CloseAudioDevice(state->recording_device_id); + SDL_CloseAudioDevice(state->playback_device_id); +} + +int audio_playback_init(audio_state* state) +{ + if (!state->recording_buffer) { + printf("Audio buffer not initialized"); + return 0; + } + + SDL_AudioDeviceID device_id = SDL_OpenAudioDevice(NULL, 0, &playback_spec, &received_playback_spec, SDL_AUDIO_ALLOW_FORMAT_CHANGE); + if (!device_id) { + printf("Failed to open playback device! SDL Error: %s", SDL_GetError()); + return 0; + } + state->playback_device_id = device_id; + + return 1; +} + +void audio_recording_callback(void* userdata, Uint8* stream, int len) +{ + char string[64]; + audio_state* state = userdata; + + int space_left = state->recording_buffer_size - state->recording_buffer_position; + if (space_left <= 0) { + sprintf(string, "Stopping recording ID: %i", state->recording_device_id); + log_message(LOG_INFO, string); + SDL_PauseAudioDevice(state->recording_device_id, 1); + return; + } + + if (len > space_left) { + len = space_left; + } + + memcpy(&state->recording_buffer[state->recording_buffer_position], stream, len); + state->recording_buffer_position += len; + + sprintf(string, "Record pos: %u/%u (%u)", state->recording_buffer_position, state->recording_buffer_size, len); + log_message(LOG_INFO, string); +} + +void audio_playback_callback(void* userdata, Uint8* stream, int len) +{ + char string[64]; + audio_state* state = userdata; + + int space_left = state->recording_buffer_size - state->recording_buffer_position; + if (space_left <= 0) { + sprintf(string, "Stopping playback ID: %i", state->recording_device_id); + log_message(LOG_INFO, string); + SDL_PauseAudioDevice(state->playback_device_id, 1); + return; + } + + if (len > space_left) { + len = space_left; + } + + memcpy(stream, &state->recording_buffer[state->recording_buffer_position], len); + state->recording_buffer_position += len; + + sprintf(string, "Playback pos: %u/%u (%u)", state->recording_buffer_position, state->recording_buffer_size, len); + log_message(LOG_INFO, string); +} diff --git a/audio.h b/audio.h new file mode 100644 index 0000000..d1afbfa --- /dev/null +++ b/audio.h @@ -0,0 +1,21 @@ +#ifndef AUDIO_H +#define AUDIO_H + +#include + +typedef struct audio_state { + int recording_device_id; + int playback_device_id; + Uint8* recording_buffer; + unsigned int recording_buffer_size; + unsigned int recording_buffer_position; +} audio_state; + +int audio_init(audio_state* state); +void audio_destroy(audio_state* state); +int audio_recording_init(audio_state* state, int index); +int audio_playback_init(audio_state* state); +void audio_recording_callback(void* userdata, Uint8* stream, int len); +void audio_playback_callback(void* userdata, Uint8* stream, int len); + +#endif diff --git a/log.h b/log.h index f8dad15..8ed0363 100644 --- a/log.h +++ b/log.h @@ -1,4 +1,7 @@ // Chat GPT code +#ifndef LOG_H +#define LOG_H + #include #include #include @@ -12,3 +15,5 @@ typedef enum { const char* get_current_time(); void log_message(LogLevel level, const char* message); + +#endif diff --git a/main.c b/main.c index c63cafb..e860762 100644 --- a/main.c +++ b/main.c @@ -2,19 +2,12 @@ #include #include -#include "log.h" +#include "texture.h" +#include "audio.h" + const int SCREEN_WIDTH = 640; const int SCREEN_HEIGHT = 480; -const int MAX_RECORDING_DEVICES = 10; -const int MAX_RECORDING_SECONDS = 1; -/* - * Application - */ -int init(); -void destroy(); -int select_device(SDL_KeyboardEvent* key_event, int max_index); - typedef enum { SELECTING_DEVICE, RECORDING, @@ -22,49 +15,23 @@ typedef enum { PLAYBACK, } application_state; -typedef struct { +typedef struct state { application_state application_state; + audio_state audio; int device_index; - int recording_device_id; - int playback_device_id; } state; +int init(); +void destroy(); +int select_device(SDL_KeyboardEvent* key_event, int max_index); + void application_state_to_string(application_state state, char* string); -/* - * Visual - */ + SDL_Window* window = NULL; SDL_Renderer* renderer = NULL; -TTF_Font* global_font = NULL; -typedef struct { - SDL_Texture* texture; - int width; - int height; -} text_texture; - -int text_texture_init(text_texture* text_texture); -int text_texture_load(text_texture* text_texture, char* string); -int text_texture_render(text_texture* text_texture, int x, int y); -int text_texture_free(text_texture* text_texture); -/* - * Audio - */ int num_devices = 0; -SDL_AudioSpec recording_spec; -SDL_AudioSpec playback_spec; -SDL_AudioSpec received_recording_spec; -SDL_AudioSpec received_playback_spec; -Uint8* recording_buffer = NULL; -unsigned int recording_buffer_size = 0; -unsigned int recording_buffer_position = 0; - -SDL_AudioDeviceID audio_recording_init(int index); -SDL_AudioDeviceID audio_playback_init(); -void audio_recording_callback( void* userdata, Uint8* stream, int len ); -void audio_playback_callback( void* userdata, Uint8* stream, int len ); - int handle_input(SDL_Event* event, state* state); void handle_task(state* state); int main(int argc, char* argv[]) @@ -76,46 +43,28 @@ int main(int argc, char* argv[]) char char_buffer[64]; char default_fmt[] = "Device selected: %i"; - state state = { - SELECTING_DEVICE, - -1, - 0, - 0, - }; + state state; + state.application_state = SELECTING_DEVICE; + audio_init(&state.audio); + state.device_index = -1; text_texture display_text_texture; - text_texture_init(&display_text_texture); + text_texture_init(&display_text_texture, renderer); sprintf(char_buffer, default_fmt, state.device_index); text_texture_load(&display_text_texture, char_buffer); text_texture device_textures[num_devices]; for (int i = 0; i < num_devices; i++) { - text_texture_init(&device_textures[i]); + text_texture_init(&device_textures[i], renderer); sprintf(char_buffer, "%i: %s", i, SDL_GetAudioDeviceName(i, 1)); text_texture_load(&device_textures[i], char_buffer); } text_texture state_text_texture; - text_texture_init(&state_text_texture); + text_texture_init(&state_text_texture, renderer); application_state_to_string(state.application_state, char_buffer); text_texture_load(&state_text_texture, char_buffer); - SDL_zero(recording_spec); - recording_spec.freq = 44100; - recording_spec.format = AUDIO_S16; - recording_spec.channels = 2; - recording_spec.samples = 4096; - recording_spec.callback = audio_recording_callback; - recording_spec.userdata = &state; - - SDL_zero(playback_spec); - playback_spec.freq = 44100; - playback_spec.format = AUDIO_S16; - playback_spec.channels = 2; - playback_spec.samples = 4096; - playback_spec.callback = audio_playback_callback; - playback_spec.userdata = &state; - SDL_Event event; while (1) { while (SDL_PollEvent(&event)) { @@ -164,8 +113,7 @@ int main(int argc, char* argv[]) cleanup: printf("Cleanup\n"); - SDL_CloseAudioDevice(state.recording_device_id); - SDL_CloseAudioDevice(state.playback_device_id); + audio_destroy(&state.audio); text_texture_free(&display_text_texture); for (int i = 0; i < num_devices; i++) { text_texture_free(&device_textures[i]); @@ -184,15 +132,12 @@ int handle_input(SDL_Event* event, state* state) switch (keysym) { case SDLK_y: case SDLK_RETURN: - /*if (state->recording_device_id)*/ - /* SDL_CloseAudioDevice(state->recording_device_id);*/ - /*state->recording_device_id = audio_recording_init(state->device_index, NULL);*/ - if (state->device_index == -1 || !state->recording_device_id) break; - SDL_LockAudioDevice(state->recording_device_id); - memset(recording_buffer, 0, recording_buffer_size); - recording_buffer_position = 0; - SDL_UnlockAudioDevice(state->recording_device_id); - SDL_PauseAudioDevice(state->recording_device_id, 0); + if (state->device_index == -1 || !state->audio.recording_device_id) break; + SDL_LockAudioDevice(state->audio.recording_device_id); + memset(state->audio.recording_buffer, 0, state->audio.recording_buffer_size); + state->audio.recording_buffer_position = 0; + SDL_UnlockAudioDevice(state->audio.recording_device_id); + SDL_PauseAudioDevice(state->audio.recording_device_id, 0); state->application_state = RECORDING; break; case SDLK_q: @@ -204,8 +149,8 @@ int handle_input(SDL_Event* event, state* state) if (device_index_new == -1) break; if (device_index_new == state->device_index) break; state->device_index = device_index_new; - SDL_CloseAudioDevice(state->recording_device_id); - state->recording_device_id = audio_recording_init(state->device_index); + SDL_CloseAudioDevice(state->audio.recording_device_id); + audio_recording_init(&state->audio, state->device_index); break; @@ -213,7 +158,7 @@ int handle_input(SDL_Event* event, state* state) switch (keysym) { case SDLK_q: case SDLK_ESCAPE: - SDL_PauseAudioDevice(state->recording_device_id, 1); + SDL_PauseAudioDevice(state->audio.recording_device_id, 1); state->application_state = SELECTING_DEVICE; break; } @@ -223,12 +168,12 @@ int handle_input(SDL_Event* event, state* state) switch (keysym) { case SDLK_y: case SDLK_RETURN: - if (!state->playback_device_id) - state->playback_device_id = audio_playback_init(); - SDL_LockAudioDevice(state->playback_device_id); - recording_buffer_position = 0; - SDL_UnlockAudioDevice(state->playback_device_id); - SDL_PauseAudioDevice(state->playback_device_id, 0); + if (!state->audio.playback_device_id) + audio_playback_init(&state->audio); + SDL_LockAudioDevice(state->audio.playback_device_id); + state->audio.recording_buffer_position = 0; + SDL_UnlockAudioDevice(state->audio.playback_device_id); + SDL_PauseAudioDevice(state->audio.playback_device_id, 0); state->application_state = PLAYBACK; break; case SDLK_q: @@ -242,7 +187,7 @@ int handle_input(SDL_Event* event, state* state) switch (keysym) { case SDLK_q: case SDLK_ESCAPE: - SDL_PauseAudioDevice(state->playback_device_id, 1); + SDL_PauseAudioDevice(state->audio.playback_device_id, 1); state->application_state = RECORDED; break; } @@ -260,7 +205,7 @@ void handle_task(state* state) break; case RECORDING: - if (recording_buffer_position >= recording_buffer_size) + if (state->audio.recording_buffer_position >= state->audio.recording_buffer_size) state->application_state = RECORDED; break; @@ -268,7 +213,7 @@ void handle_task(state* state) break; case PLAYBACK: - if (recording_buffer_position >= recording_buffer_size) + if (state->audio.recording_buffer_position >= state->audio.recording_buffer_size) state->application_state = RECORDED; break; @@ -302,20 +247,11 @@ int init() return 0; } - global_font = TTF_OpenFont("FiraCode-Regular.ttf", 24); - if (!global_font) { - printf("Failed to load font! TTF_Error: %s\n", TTF_GetError()); - return 0; - } - return 1; } void destroy() { - free(recording_buffer); - - TTF_CloseFont(global_font); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); TTF_Quit(); @@ -325,11 +261,12 @@ void destroy() int select_device(SDL_KeyboardEvent* key_event, int max_index) { SDL_Keycode keycode = key_event->keysym.sym; - SDL_Keycode mod = key_event->keysym.mod; + /*SDL_Keycode mod = key_event->keysym.mod;*/ int keycode_is_num = (keycode >= SDLK_0 && keycode <= SDLK_9); - int no_mod = (mod == 0); - if (!keycode_is_num || !no_mod) { + /*int no_mod = (mod == 0);*/ + /*if (!keycode_is_num || !no_mod) {*/ + if (!keycode_is_num) { printf("Not number: %c <%u>\n", keycode, keycode); return -1; } else { @@ -359,158 +296,3 @@ void application_state_to_string(application_state state, char* string) break; } } - -int text_texture_init(text_texture* text_texture) -{ - text_texture->texture = NULL; - text_texture->width = 0; - text_texture->height = 0; - return 1; -} - -int text_texture_load(text_texture* text_texture, char* string) -{ - if (text_texture->texture) { - SDL_DestroyTexture(text_texture->texture); - text_texture->texture = NULL; - } - - SDL_Color text_color = { 255, 255, 255 }; - SDL_Surface* text_surface = TTF_RenderText_Solid(global_font, string, text_color); - if (!text_surface) { - printf("Unable to render text surface! TTF_Error: %s\n", TTF_GetError()); - return 0; - } - - SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, text_surface); - if (!texture) { - printf("Unable to create texture from rendered text! SDL_Error: %s\n", SDL_GetError()); - return 0; - } - - text_texture->texture = SDL_CreateTextureFromSurface(renderer, text_surface); - text_texture->width = text_surface->w; - text_texture->height = text_surface->h; - - SDL_FreeSurface(text_surface); - return 1; -} - -int text_texture_render(text_texture* text_texture, int x, int y) -{ - if (!text_texture) { - printf("text_texture uninitialized"); - return 0; - } - if (!text_texture->texture) { - printf("text_texture->texture uninitialized"); - return 0; - } - - int quad_width = text_texture->width; - int quad_height = text_texture->height; - SDL_Rect render_quad = { x, y, quad_width, quad_height }; - SDL_RenderCopy(renderer, text_texture->texture, NULL, &render_quad); - - return 1; -} - -int text_texture_free(text_texture* text_texture) -{ - if (!text_texture->texture) { - return 0; - } - SDL_DestroyTexture(text_texture->texture); - return 1; -} - -SDL_AudioDeviceID audio_recording_init(int index) -{ - SDL_AudioDeviceID device_id = SDL_OpenAudioDevice(SDL_GetAudioDeviceName(index, 1), 1, &recording_spec, &received_recording_spec, SDL_AUDIO_ALLOW_FORMAT_CHANGE); - printf("Recording Device: %s\n", SDL_GetAudioDeviceName(index, 1)); - if (!device_id) { - printf("Failed to open recording device! SDL Error: %s", SDL_GetError()); - return 0; - } - - unsigned int bytes_per_sample = received_recording_spec.channels * (SDL_AUDIO_BITSIZE(received_recording_spec.format)/8); - unsigned int bytes_per_second = received_recording_spec.freq * bytes_per_sample; - recording_buffer_size = MAX_RECORDING_SECONDS * bytes_per_second; - - if (recording_buffer) free(recording_buffer); - recording_buffer = malloc(recording_buffer_size); - memset(recording_buffer, 0, recording_buffer_size); - - return device_id; -} - -SDL_AudioDeviceID audio_playback_init() -{ - if (!recording_buffer) { - printf("Audio buffer not initialized"); - return 0; - } - - SDL_AudioDeviceID device_id = SDL_OpenAudioDevice(NULL, 0, &playback_spec, &received_playback_spec, SDL_AUDIO_ALLOW_FORMAT_CHANGE); - if (!device_id) { - printf("Failed to open playback device! SDL Error: %s", SDL_GetError()); - return 0; - } - - return device_id; -} - -int audio_device_stop(int device_id) -{ - SDL_PauseAudioDevice(device_id, 1); - SDL_CloseAudioDevice(device_id); - return 1; -} - -void audio_recording_callback(void* userdata, Uint8* stream, int len) -{ - char string[64]; - state* state = userdata; - - int space_left = recording_buffer_size - recording_buffer_position; - if (space_left <= 0) { - sprintf(string, "Stopping recording ID: %i", state->recording_device_id); - log_message(LOG_INFO, string); - SDL_PauseAudioDevice(state->recording_device_id, 1); - return; - } - - if (len > space_left) { - len = space_left; - } - - memcpy(&recording_buffer[recording_buffer_position], stream, len); - recording_buffer_position += len; - - sprintf(string, "Record pos: %u/%u (%u)", recording_buffer_position, recording_buffer_size, len); - log_message(LOG_INFO, string); -} - -void audio_playback_callback(void* userdata, Uint8* stream, int len) -{ - char string[64]; - state* state = userdata; - - int space_left = recording_buffer_size - recording_buffer_position; - if (space_left <= 0) { - sprintf(string, "Stopping playback ID: %i", state->recording_device_id); - log_message(LOG_INFO, string); - SDL_PauseAudioDevice(state->playback_device_id, 1); - return; - } - - if (len > space_left) { - len = space_left; - } - - memcpy(stream, &recording_buffer[recording_buffer_position], len); - recording_buffer_position += len; - - sprintf(string, "Playback pos: %u/%u (%u)", recording_buffer_position, recording_buffer_size, len); - log_message(LOG_INFO, string); -} diff --git a/makefile b/makefile index 2b66093..e33dda6 100644 --- a/makefile +++ b/makefile @@ -21,8 +21,13 @@ $(OBJS): $(OBJD)/%.o: %.c mkdir -p $(@D) $(CC) $(CCFLAGS) -c $? -o $@ +TARGET1 = test + +$(TARGET1): example-test-code/audiotest.c + $(CC) $(CCFLAGS) $^ -o $(TARGET1) $(LDFLAGS) + clean: - rm -r $(TARGET) $(OBJD) + rm -r $(TARGET) $(TARGET1) $(test) $(OBJD) run: $(TARGET) ./$(TARGET) diff --git a/texture.c b/texture.c new file mode 100644 index 0000000..ba1bb13 --- /dev/null +++ b/texture.c @@ -0,0 +1,71 @@ +#include "texture.h" + +int text_texture_init(text_texture* text_texture, SDL_Renderer* renderer) +{ + text_texture->texture = NULL; + text_texture->renderer = renderer; + text_texture->font = TTF_OpenFont("FiraCode-Regular.ttf", 24); + if (!text_texture->font) { + printf("Failed to load font! TTF_Error: %s\n", TTF_GetError()); + return 0; + } + text_texture->width = 0; + text_texture->height = 0; + return 1; +} + +int text_texture_load(text_texture* text_texture, char* string) +{ + if (text_texture->texture) { + SDL_DestroyTexture(text_texture->texture); + text_texture->texture = NULL; + } + + SDL_Color text_color = { 255, 255, 255 }; + SDL_Surface* text_surface = TTF_RenderText_Solid(text_texture->font, string, text_color); + if (!text_surface) { + printf("Unable to render text surface! TTF_Error: %s\n", TTF_GetError()); + return 0; + } + + SDL_Texture* texture = SDL_CreateTextureFromSurface(text_texture->renderer, text_surface); + if (!texture) { + printf("Unable to create texture from rendered text! SDL_Error: %s\n", SDL_GetError()); + return 0; + } + + text_texture->texture = SDL_CreateTextureFromSurface(text_texture->renderer, text_surface); + text_texture->width = text_surface->w; + text_texture->height = text_surface->h; + + SDL_FreeSurface(text_surface); + return 1; +} + +int text_texture_render(text_texture* text_texture, int x, int y) +{ + if (!text_texture) { + printf("text_texture uninitialized"); + return 0; + } + if (!text_texture->texture) { + printf("text_texture->texture uninitialized"); + return 0; + } + + int quad_width = text_texture->width; + int quad_height = text_texture->height; + SDL_Rect render_quad = { x, y, quad_width, quad_height }; + SDL_RenderCopy(text_texture->renderer, text_texture->texture, NULL, &render_quad); + + return 1; +} + +int text_texture_free(text_texture* text_texture) +{ + if (!text_texture->texture) { + return 0; + } + SDL_DestroyTexture(text_texture->texture); + return 1; +} diff --git a/texture.h b/texture.h new file mode 100644 index 0000000..aa9be5f --- /dev/null +++ b/texture.h @@ -0,0 +1,20 @@ +#ifndef TEXTURE_H +#define TEXTURE_H + +#include +#include "SDL2/SDL.h" + +typedef struct { + SDL_Texture* texture; + SDL_Renderer* renderer; + TTF_Font* font; + int width; + int height; +} text_texture; + +int text_texture_init(text_texture* text_texture, SDL_Renderer* renderer); +int text_texture_load(text_texture* text_texture, char* string); +int text_texture_render(text_texture* text_texture, int x, int y); +int text_texture_free(text_texture* text_texture); + +#endif