sdl-audio/main.c

299 lines
7.2 KiB
C

#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <stdio.h>
#include "texture.h"
#include "audio.h"
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
typedef enum {
SELECTING_DEVICE,
RECORDING,
RECORDED,
PLAYBACK,
} application_state;
typedef struct state {
application_state application_state;
audio_state audio;
int device_index;
} 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);
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
int num_devices = 0;
int handle_input(SDL_Event* event, state* state);
void handle_task(state* state);
int main(int argc, char* argv[])
{
if (!init()) return 1;
num_devices = SDL_GetNumAudioDevices(1);
printf("Num audio devices: %i\n", num_devices);
char char_buffer[64];
char default_fmt[] = "Device selected: %i";
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, 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], 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, renderer);
application_state_to_string(state.application_state, char_buffer);
text_texture_load(&state_text_texture, char_buffer);
SDL_Event event;
while (1) {
while (SDL_PollEvent(&event)) {
SDL_Keycode keysym = event.key.keysym.sym;
switch (event.type) {
case SDL_QUIT:
goto cleanup;
break;
case SDL_KEYDOWN:
if (!handle_input(&event, &state)) goto cleanup;
break;
}
}
handle_task(&state);
sprintf(char_buffer, default_fmt, state.device_index);
text_texture_load(&display_text_texture, char_buffer);
application_state_to_string(state.application_state, char_buffer);
text_texture_load(&state_text_texture, char_buffer);
// Clear the screen
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
// Render
text_texture_render(&display_text_texture, 0, 0);
if (state.application_state == SELECTING_DEVICE) {
int text_y_offset_step = display_text_texture.height * 2;
int text_y_offset = text_y_offset_step;
for (int i = 0; i < num_devices; i++) {
text_texture_render(&device_textures[i], 0, text_y_offset);
text_y_offset += text_y_offset_step;
}
}
text_texture_render(&state_text_texture, 0, SCREEN_HEIGHT - state_text_texture.height);
// Update the screen
SDL_RenderPresent(renderer);
}
cleanup:
printf("Cleanup\n");
audio_destroy(&state.audio);
text_texture_free(&display_text_texture);
for (int i = 0; i < num_devices; i++) {
text_texture_free(&device_textures[i]);
}
destroy();
return 0;
}
int handle_input(SDL_Event* event, state* state)
{
SDL_Keycode keysym = event->key.keysym.sym;
switch (state->application_state) {
case SELECTING_DEVICE:
switch (keysym) {
case SDLK_y:
case SDLK_RETURN:
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:
case SDLK_ESCAPE:
return 0;
break;
}
int device_index_new = select_device(&event->key, num_devices);
if (device_index_new == -1) break;
if (device_index_new == state->device_index) break;
state->device_index = device_index_new;
SDL_CloseAudioDevice(state->audio.recording_device_id);
audio_recording_init(&state->audio, state->device_index);
break;
case RECORDING:
switch (keysym) {
case SDLK_q:
case SDLK_ESCAPE:
SDL_PauseAudioDevice(state->audio.recording_device_id, 1);
state->application_state = SELECTING_DEVICE;
break;
}
break;
case RECORDED:
switch (keysym) {
case SDLK_y:
case SDLK_RETURN:
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:
case SDLK_ESCAPE:
state->application_state = SELECTING_DEVICE;
break;
}
break;
case PLAYBACK:
switch (keysym) {
case SDLK_q:
case SDLK_ESCAPE:
SDL_PauseAudioDevice(state->audio.playback_device_id, 1);
state->application_state = RECORDED;
break;
}
break;
}
return 1;
}
void handle_task(state* state)
{
switch (state->application_state) {
case SELECTING_DEVICE:
break;
case RECORDING:
if (state->audio.recording_buffer_position >= state->audio.recording_buffer_size)
state->application_state = RECORDED;
break;
case RECORDED:
break;
case PLAYBACK:
if (state->audio.recording_buffer_position >= state->audio.recording_buffer_size)
state->application_state = RECORDED;
break;
}
}
int init()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
return 0;
}
if (TTF_Init() == -1) {
printf("TTF could not initialize! TTF Error: %s\n", TTF_GetError());
return 0;
}
window = SDL_CreateWindow("SDL record", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH,
SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (!window) {
printf("Window could not be created! SDL Error: %s\n", SDL_GetError());
return 0;
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (!renderer) {
printf("Renderer could not be created! SDL_Error: %s\n", SDL_GetError());
return 0;
}
return 1;
}
void destroy()
{
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
TTF_Quit();
SDL_Quit();
}
int select_device(SDL_KeyboardEvent* key_event, int max_index)
{
SDL_Keycode keycode = key_event->keysym.sym;
/*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) {*/
if (!keycode_is_num) {
printf("Not number: %c <%u>\n", keycode, keycode);
return -1;
} else {
printf("Is number: %c <%u>\n", keycode, keycode);
}
int index = keycode - SDLK_0;
if (index >= max_index) return -1;
return index;
}
void application_state_to_string(application_state state, char* string)
{
switch (state) {
case SELECTING_DEVICE:
sprintf(string, "Selecting Device [0-9] -> [y/RET], ");
break;
case RECORDING:
sprintf(string, "Recording [ESC] to cancel");
break;
case RECORDED:
sprintf(string, "Recorded [y/RET] to play [ESC] to Select");
break;
case PLAYBACK:
sprintf(string, "Playing");
break;
}
}