299 lines
7.2 KiB
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;
|
|
}
|
|
}
|