commit 5df346e342841284e6438585b35e7a969d28abef Author: Mark Allyn Date: Fri Mar 27 10:26:47 2026 -0700 initial commit diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f2b3c37 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,51 @@ +cmake_minimum_required (VERSION 3.22) + +set (CMAKE_CXX_STANDARD 11) + +cmake_policy(SET CMP0072 NEW) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") +project (scope) + +# SDL2 +find_package(SDL2 REQUIRED) +# find_package(SDL_ttf REQUIRED) + +# Pulse + +find_path(PULSEAUDIO_INCLUDE_DIR + NAMES pulse/pulseaudio.h + DOC "The PulseAudio include directory" + ) +find_library(PULSEAUDIO_LIBRARY + NAMES pulse + DOC "The PulseAudio library" + ) + +include_directories(${PULSEAUDIO_INCLUDE_DIRS}) + +include_directories(${SDL2_INCLUDE_DIRS}) +# include_directories(${SDL_TTF_INCLUDE_DIRS}) + +message(STATUS "<<${SDL2_INCLUDE_DIRS}>>") +# message(STATUS "<<${OPENGL_INCLUDE_DIR}>>") + +# Main Executable + +add_definitions("-Wall -O0 -g") +#add_definitions("-Wall -Werror -O0 -g") +add_executable(scope main_buffer_manager_class.cpp audio_buffer_manager_class.cpp + spectrum_buffer_manager_class.cpp piano_process.cpp + main_class.cpp piano_class.cpp spectrum_class.cpp + audio_class.cpp scope.cpp) + +target_include_directories(scope PUBLIC ${CMAKE_SOURCE_DIR}/src) + +# Libraries +target_link_libraries(scope ${SDL2_LIBRARIES}) +target_link_libraries(scope m /usr/lib/) +target_link_libraries(scope /usr/lib/x86_64-linux-gnu/libSDL2_ttf-2.0.so) +# target_link_libraries(scope ${SDL_TTF_LIBRARIES}) +target_link_libraries(scope pulse-simple pulse) +target_link_libraries(scope fftw3) + +message(STATUS "<<${SDL2_LIBRARIES}>>") diff --git a/CMakeLists.txt.save b/CMakeLists.txt.save new file mode 100644 index 0000000..0107929 --- /dev/null +++ b/CMakeLists.txt.save @@ -0,0 +1,31 @@ +cmake_minimum_required (VERSION 3.2) + +set (CMAKE_CXX_STANDARD 11) + +cmake_policy(SET CMP0072 NEW) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") +project (attempt1) + +# SDL2 +find_package(SDL2 REQUIRED) +# find_package(OpenGL REQUIRED) + +include_directories(${SDL2_INCLUDE_DIRS}) +# include_directories(${OPENGL_INCLUDE_DIR}) + +message(STATUS "<<${SDL2_INCLUDE_DIRS}>>") +# message(STATUS "<<${OPENGL_INCLUDE_DIR}>>") + +# Main Executable + +add_definitions("-Wall -O0 -g") +#add_definitions("-Wall -Werror -O0 -g") +add_executable(attempt1 attempt1.cpp) +target_include_directories(attempt1 PUBLIC ${CMAKE_SOURCE_DIR}/src) + +# Libraries +target_link_libraries(attempt1 ${SDL2_LIBRARIES}) +# target_link_libraries(attempt1 ${OPENGL_LIBRARIES}) + +message(STATUS "<<${SDL2_LIBRARIES}>>") +# message(STATUS "<<${OPENGL_LIBRARIES}>>") diff --git a/CMakeLists.txt.testing b/CMakeLists.txt.testing new file mode 100644 index 0000000..3803a45 --- /dev/null +++ b/CMakeLists.txt.testing @@ -0,0 +1,31 @@ +cmake_minimum_required (VERSION 3.2) + +set (CMAKE_CXX_STANDARD 11) + +cmake_policy(SET CMP0072 NEW) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") +project (mark1) + +# SDL2 +find_package(SDL2 REQUIRED) +# find_package(OpenGL REQUIRED) + +include_directories(${SDL2_INCLUDE_DIRS}) +# include_directories(${OPENGL_INCLUDE_DIR}) + +message(STATUS "<<${SDL2_INCLUDE_DIRS}>>") +# message(STATUS "<<${OPENGL_INCLUDE_DIR}>>") + +# Main Executable + +add_definitions("-Wall -O0 -g") +#add_definitions("-Wall -Werror -O0 -g") +add_executable(mark1 mark1.cpp) +target_include_directories(mark1 PUBLIC ${CMAKE_SOURCE_DIR}/src) + +# Libraries +target_link_libraries(mark1 ${SDL2_LIBRARIES}) +# target_link_libraries(mark1 ${OPENGL_LIBRARIES}) + +message(STATUS "<<${SDL2_LIBRARIES}>>") +# message(STATUS "<<${OPENGL_LIBRARIES}>>") diff --git a/audio_buffer_manager_class.cpp b/audio_buffer_manager_class.cpp new file mode 100644 index 0000000..fb58d25 --- /dev/null +++ b/audio_buffer_manager_class.cpp @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scope.h" + +audio_buffer_manager_class::audio_buffer_manager_class() + { + my_formatted_audio_buffer = NULL; + } + +audio_buffer_manager_class::~audio_buffer_manager_class() + { + if (my_formatted_audio_buffer != NULL) + { + free(my_formatted_audio_buffer); + } + } + +int audio_buffer_manager_class::initialize_audio(int horizontal_size, + int vertical_size, Sint16 *main_buffer) + { + my_formatted_audio_buffer = (int *)malloc ((sizeof(int) * AUDIO_BUFFER_SIZE)); + if (my_formatted_audio_buffer == NULL) + { + printf ("cannot allocate formatted audio audio buffer\n"); + perror ("error is"); + return 1; + } + my_audio_horizontal_size = horizontal_size; + my_audio_vertical_size = vertical_size; + my_main_buffer = main_buffer; + return 0; + } + +int *audio_buffer_manager_class::process_audio() + { + my_read_audio_index = 0; + + // Transform Sint16 to int for each element + for (my_read_audio_index = 0; my_read_audio_index < my_audio_horizontal_size; + my_read_audio_index += 1) + { + audio_holding = *(my_main_buffer + my_read_audio_index); + *(my_formatted_audio_buffer + my_read_audio_index) = (int)audio_holding; + } + + return my_formatted_audio_buffer; + } + diff --git a/audio_class.cpp b/audio_class.cpp new file mode 100644 index 0000000..76b9c87 --- /dev/null +++ b/audio_class.cpp @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "scope.h" + +// Audio class method bodies +// Audio window + +int audio_window_class::draw_trace(int *audio_data, int audio_data_size) + { + int audio_data_counter; + int *current_audio_data_value; + int *prev_audio_data_value; + int this_audio_data_size; + + if (audio_data_size >= max_audio_trace_width) + { + this_audio_data_size = max_audio_trace_width; + } + else + { + this_audio_data_size = audio_data_size; + } + + //printf("this size %d\n", this_audio_data_size); + //Clear the window + + SDL_SetRenderDrawColor(renderer_for_audio, (Uint8)40, (Uint8)40, (Uint8)0, (Uint8)255); + SDL_RenderClear(renderer_for_audio); + + // Render word Oscilloscope + SDL_RenderCopy(renderer_for_audio, texture_for_audio, NULL, &rect_for_audio); + + // green trace + SDL_SetRenderDrawColor(renderer_for_audio, (Uint8)0, (Uint8)(255), (Uint8)0, (Uint8)255); + + for (audio_data_counter = 1; audio_data_counter < this_audio_data_size; audio_data_counter += 1) + { + current_audio_data_value = audio_data + audio_data_counter; + prev_audio_data_value = audio_data + audio_data_counter - 1; + SDL_RenderDrawLine (renderer_for_audio, x_audio_window_trace_base + audio_data_counter -1, + y_audio_window_trace_base + *prev_audio_data_value, + x_audio_window_trace_base + audio_data_counter, + y_audio_window_trace_base + *current_audio_data_value); + } + + SDL_RenderPresent(renderer_for_audio); + return 0; + } + +int audio_window_class::get_max_audio_trace_width() + { + return max_audio_trace_width; + } + +int audio_window_class::get_max_audio_trace_height() + { + return max_audio_trace_height; + } + + +audio_window_class::audio_window_class (int x_main_window_size, int y_main_window_size) + { + x_audio_window_position = 5; + y_audio_window_position = 5; + x_audio_window_size = ((int)(x_main_window_size / 2)) - 20; + y_audio_window_size = (((int)(y_main_window_size / 3)) * 2) - 10; + x_audio_window_trace_base = x_audio_window_position; + y_audio_window_trace_base = (int)(y_audio_window_size / 2) + y_audio_window_position; + max_audio_trace_width = x_audio_window_size; + max_audio_trace_height = y_audio_window_size; + if ((window_for_audio = SDL_CreateWindow("Oscilloscope", + x_audio_window_position, y_audio_window_position, + x_audio_window_size, y_audio_window_size,0)) == NULL) { + printf("error opening audio window SDL: %s\n", SDL_GetError()); + exit (0); + } + + printf("audio window: window_size %d x pos %d max trace width %d\n", + x_audio_window_size, x_audio_window_position, max_audio_trace_width); + + SDL_SetWindowBordered(window_for_audio, SDL_FALSE); + + if ((renderer_for_audio = SDL_CreateRenderer(window_for_audio, -1, 0)) == NULL) { + printf("error opening audio renderer SDL: %s\n", SDL_GetError()); + exit (0); + } + + if ((font_for_audio = TTF_OpenFont("/usr/share/fonts/truetype/freefont/FreeSans.ttf", + 24)) == NULL) { + printf("error opening audio font SDL: %s\n", SDL_GetError()); + exit (0); + } + + color_for_audio = {255,255,255}; + + if ((surface_for_audio = TTF_RenderText_Solid(font_for_audio, + "OSCILLOSCOPE", color_for_audio)) == NULL) { + printf("error opening audio surface SDL: %s\n", SDL_GetError()); + exit (0); + } + + + if ((texture_for_audio = SDL_CreateTextureFromSurface(renderer_for_audio, + surface_for_audio)) == NULL) { + printf("error opening audio texture SDL: %s\n", SDL_GetError()); + exit (0); + } + + rect_for_audio.x = x_audio_window_trace_base + ((int)(max_audio_trace_width/2) - + (int)(surface_for_audio->w / 2)); + rect_for_audio.y = 20; + rect_for_audio.w = surface_for_audio->w; + rect_for_audio.h = surface_for_audio->h; + + SDL_SetRenderDrawColor(renderer_for_audio, (Uint8)40, (Uint8)40, (Uint8)0, (Uint8)255); + + SDL_RenderClear(renderer_for_audio); + SDL_RenderCopy(renderer_for_audio, texture_for_audio, NULL, &rect_for_audio); + + SDL_RenderPresent(renderer_for_audio); + } diff --git a/do_run.sh b/do_run.sh new file mode 100755 index 0000000..05a56b8 --- /dev/null +++ b/do_run.sh @@ -0,0 +1 @@ +/home/maallyn/sound-scope/sdl2/fft/build/scope 1700 1000 diff --git a/keyboard-key-blank.bmp b/keyboard-key-blank.bmp new file mode 100755 index 0000000..d99ed63 Binary files /dev/null and b/keyboard-key-blank.bmp differ diff --git a/keyboard-key1.bmp b/keyboard-key1.bmp new file mode 100755 index 0000000..d653b20 Binary files /dev/null and b/keyboard-key1.bmp differ diff --git a/keyboard-key10.bmp b/keyboard-key10.bmp new file mode 100755 index 0000000..55e1f13 Binary files /dev/null and b/keyboard-key10.bmp differ diff --git a/keyboard-key11.bmp b/keyboard-key11.bmp new file mode 100755 index 0000000..cb157d9 Binary files /dev/null and b/keyboard-key11.bmp differ diff --git a/keyboard-key12.bmp b/keyboard-key12.bmp new file mode 100755 index 0000000..c6191e1 Binary files /dev/null and b/keyboard-key12.bmp differ diff --git a/keyboard-key2.bmp b/keyboard-key2.bmp new file mode 100755 index 0000000..536918e Binary files /dev/null and b/keyboard-key2.bmp differ diff --git a/keyboard-key3.bmp b/keyboard-key3.bmp new file mode 100755 index 0000000..3a339ad Binary files /dev/null and b/keyboard-key3.bmp differ diff --git a/keyboard-key4.bmp b/keyboard-key4.bmp new file mode 100755 index 0000000..ad8304a Binary files /dev/null and b/keyboard-key4.bmp differ diff --git a/keyboard-key5.bmp b/keyboard-key5.bmp new file mode 100755 index 0000000..f5d7e30 Binary files /dev/null and b/keyboard-key5.bmp differ diff --git a/keyboard-key6.bmp b/keyboard-key6.bmp new file mode 100755 index 0000000..1e6019a Binary files /dev/null and b/keyboard-key6.bmp differ diff --git a/keyboard-key7.bmp b/keyboard-key7.bmp new file mode 100755 index 0000000..53bf196 Binary files /dev/null and b/keyboard-key7.bmp differ diff --git a/keyboard-key8.bmp b/keyboard-key8.bmp new file mode 100755 index 0000000..ee36c15 Binary files /dev/null and b/keyboard-key8.bmp differ diff --git a/keyboard-key9.bmp b/keyboard-key9.bmp new file mode 100755 index 0000000..e13a622 Binary files /dev/null and b/keyboard-key9.bmp differ diff --git a/main_buffer_manager_class.cpp b/main_buffer_manager_class.cpp new file mode 100644 index 0000000..17504f1 --- /dev/null +++ b/main_buffer_manager_class.cpp @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scope.h" + +// Pulse +static const pa_sample_spec my_pa_spec = { + .format = PA_SAMPLE_S16LE, + .rate = 44100, + .channels = 1 + }; + +// audio buffer +main_buffer_manager_class::main_buffer_manager_class() + { + my_read_main_buffer = NULL; + } + +main_buffer_manager_class::~main_buffer_manager_class() + { + if (my_read_main_buffer != NULL) + { + free(my_read_main_buffer); + } + } + +Sint16 *main_buffer_manager_class::initial_preparation() + { + my_read_main_buffer = (Sint16 *)malloc ((sizeof(Sint16) * READ_BUFFER_SIZE)); + if (my_read_main_buffer == NULL) + { + printf ("cannot allocate read buffer\n"); + perror ("error is"); + return NULL; + } + + // Open pulse + pulse_s = pa_simple_new(NULL,"scope sound", PA_STREAM_RECORD, NULL, "record", + &my_pa_spec, NULL, NULL, &function_return); + + if (pulse_s == NULL) { + printf("pa_simple_new() failed: %s\n", pa_strerror(function_return)); + return NULL; + } + + return my_read_main_buffer; + } + +Sint16 *main_buffer_manager_class::read_main_buffer() + { + + // grab the buffer from the audio device + printf("about to grab sound\n"); + if (pa_simple_read(pulse_s, (Uint8 *)my_read_main_buffer, + (READ_BUFFER_SIZE * sizeof(Sint16)), &function_return) < 0) { + printf("sound read failed %s\n", pa_strerror(function_return)); + return NULL; + } + + printf("just grabbed the buffer from device\n"); + // Turn the volume down + for (main_buffer_index = 0; main_buffer_index < READ_BUFFER_SIZE; + main_buffer_index += 1) + { + main_buffer_hold = (Sint16)(*(my_read_main_buffer + main_buffer_index) * MAIN_VOLUME); + *(my_read_main_buffer + main_buffer_index) = main_buffer_hold; + } + + return my_read_main_buffer; + } diff --git a/main_class.cpp b/main_class.cpp new file mode 100644 index 0000000..8450d36 --- /dev/null +++ b/main_class.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scope.h" + +// Main window +main_window_class::main_window_class (int x_main_window_size, int y_main_window_size) + { + if ((window_for_main = SDL_CreateWindow("Audio Analyzer", + 0, 0, x_main_window_size, y_main_window_size, 0)) == NULL) { + printf("error opening main window SDL: %s\n", SDL_GetError()); + exit (0); + } + + //if ((call_result = SDL_SetWindowFullscreen(window_for_main, + // SDL_WINDOW_FULLSCREEN_DESKTOP)) !=0) { + // printf("error setting main to fullscreen SDL: %s\n", SDL_GetError()); + // exit (0); + //} + + SDL_SetWindowBordered(window_for_main, SDL_FALSE); + + if ((renderer_for_main = SDL_CreateRenderer(window_for_main, -1, 0)) == NULL) { + printf("error opening main renderer SDL: %s\n", SDL_GetError()); + exit (0); + } + + + SDL_SetRenderDrawColor(renderer_for_main, (Uint8)30, (Uint8)50, (Uint8)50, (Uint8)255); + SDL_RenderClear(renderer_for_main); + SDL_RenderPresent(renderer_for_main); + } diff --git a/octive-1.bmp b/octive-1.bmp new file mode 100755 index 0000000..11760bb Binary files /dev/null and b/octive-1.bmp differ diff --git a/octive-2.bmp b/octive-2.bmp new file mode 100755 index 0000000..edac1ca Binary files /dev/null and b/octive-2.bmp differ diff --git a/octive-3.bmp b/octive-3.bmp new file mode 100755 index 0000000..16d15d8 Binary files /dev/null and b/octive-3.bmp differ diff --git a/octive-4.bmp b/octive-4.bmp new file mode 100755 index 0000000..7cac709 Binary files /dev/null and b/octive-4.bmp differ diff --git a/octive-5.bmp b/octive-5.bmp new file mode 100755 index 0000000..a9e996b Binary files /dev/null and b/octive-5.bmp differ diff --git a/octive-6.bmp b/octive-6.bmp new file mode 100755 index 0000000..d01e716 Binary files /dev/null and b/octive-6.bmp differ diff --git a/octive-7.bmp b/octive-7.bmp new file mode 100755 index 0000000..a962da6 Binary files /dev/null and b/octive-7.bmp differ diff --git a/octive-8.bmp b/octive-8.bmp new file mode 100755 index 0000000..20e48e5 Binary files /dev/null and b/octive-8.bmp differ diff --git a/octive-blank.bmp b/octive-blank.bmp new file mode 100755 index 0000000..72eef48 Binary files /dev/null and b/octive-blank.bmp differ diff --git a/piano-keys.bmp b/piano-keys.bmp new file mode 100755 index 0000000..eb5f2da Binary files /dev/null and b/piano-keys.bmp differ diff --git a/piano_class.cpp b/piano_class.cpp new file mode 100644 index 0000000..eadad4d --- /dev/null +++ b/piano_class.cpp @@ -0,0 +1,232 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "scope.h" + +// Piano class method bodies +// Piano window + +int piano_window_class::draw_trace(piano_data_struct *input_piano_data) + { + //printf("this size %d\n", this_piano_data_size); + //Clear the window + SDL_SetRenderDrawColor(renderer_for_piano, (Uint8)40, (Uint8)40, (Uint8)0, (Uint8)255); + SDL_RenderClear(renderer_for_piano); + + // Render word Piano + // SDL_RenderCopy(renderer_for_piano, texture_for_piano, NULL, &rect_for_piano_text); + + my_piano_data = input_piano_data; + + // point to piano_key_texture + if (my_piano_data->keyboard_key == 0) + { + texture_current_piano_light = texture_key_blank; + } + else + { + texture_current_piano_light = texture_keys[my_piano_data->keyboard_key - 1]; + } + + // point to octive_texture + if (my_piano_data->octive == 0) + { + texture_current_octive_light = texture_octive_blank; + } + else + { + texture_current_octive_light = texture_octives[my_piano_data->octive - 1]; + } + + // Put on screen + SDL_RenderCopy(renderer_for_piano, texture_current_piano_light, NULL, &rect_for_keys); + SDL_RenderCopy(renderer_for_piano, texture_current_octive_light, NULL, &rect_for_octives); + + SDL_RenderPresent(renderer_for_piano); + return 0; + } + +int piano_window_class::get_max_piano_trace_width() + { + return max_piano_trace_width; + } + +int piano_window_class::get_max_piano_trace_height() + { + return max_piano_trace_height; + } + + +piano_window_class::piano_window_class (int x_main_window_size, int y_main_window_size) + { + x_piano_window_position = 15; + y_piano_window_position = (int)((y_main_window_size / 3) * 2) + 30; + x_piano_window_size = x_main_window_size - 40; + y_piano_window_size = (((int)(y_main_window_size / 3)) * 1) - 10; + x_piano_window_trace_base = 1; + y_piano_window_trace_base = y_piano_window_size - 2; + max_piano_trace_width = x_piano_window_size - 2; + max_piano_trace_height = y_piano_window_size; + if ((window_for_piano = SDL_CreateWindow("Piano", + x_piano_window_position, y_piano_window_position, + x_piano_window_size, y_piano_window_size,0)) == NULL) { + printf("error opening piano window SDL: %s\n", SDL_GetError()); + exit (0); + } + + printf("piano window: window_size %d x pos %d max trace width %d\n", + x_piano_window_size, x_piano_window_position, max_piano_trace_width); + + SDL_SetWindowBordered(window_for_piano, SDL_FALSE); + + if ((renderer_for_piano = SDL_CreateRenderer(window_for_piano, -1, 0)) == NULL) { + printf("error opening piano renderer SDL: %s\n", SDL_GetError()); + exit (0); + } + + // Working on the title text + + if ((font_for_piano = TTF_OpenFont("/usr/share/fonts/truetype/freefont/FreeSans.ttf", + 24)) == NULL) { + printf("error opening piano font SDL: %s\n", SDL_GetError()); + exit (0); + } + + color_for_piano = {255,255,255}; + + if ((surface_for_piano_text = TTF_RenderText_Solid(font_for_piano, + "PIANO KEYBOARD", color_for_piano)) == NULL) { + printf("error opening piano surface SDL: %s\n", SDL_GetError()); + exit (0); + } + + if ((texture_for_piano = SDL_CreateTextureFromSurface(renderer_for_piano, + surface_for_piano_text)) == NULL) { + printf("error opening piano texture SDL: %s\n", SDL_GetError()); + exit (0); + } + + rect_for_piano_text.x = x_piano_window_trace_base + 5; + rect_for_piano_text.y = 20; + rect_for_piano_text.w = surface_for_piano_text->w; + rect_for_piano_text.h = surface_for_piano_text->h; + + // Load all images + // Load blanks + surface_key_blank = SDL_LoadBMP( + "/home/maallyn/sound-scope/sdl2/fft/keyboard-key-blank.bmp"); + + if (surface_key_blank == NULL) { + printf("cannot load keyboard blank keymap file\n"); + printf("%s\n",SDL_GetError()); + printf("\n"); + exit (0); + } + + surface_octive_blank = SDL_LoadBMP( + "/home/maallyn/sound-scope/sdl2/fft/octive-blank.bmp"); + + if (surface_octive_blank == NULL) { + printf("cannot load octive blank keymap file\n"); + printf("%s\n",SDL_GetError()); + printf("\n"); + exit (0); + } + + // Scale the rect for all keyboards (all same size) + rect_for_keys.w = (int)(surface_key_blank->w * PIANO_SIZE_MULTIPLY); + rect_for_keys.h = (int)(surface_key_blank->h * PIANO_SIZE_MULTIPLY); + rect_for_keys.x = KEYBOARD_POSITION_X; + rect_for_keys.y = KEYBOARD_POSITION_Y; + + // Scale the rect for all octives (all same size) + rect_for_octives.w = (int)(surface_octive_blank->w * PIANO_SIZE_MULTIPLY); + rect_for_octives.h = (int)(surface_octive_blank->h * PIANO_SIZE_MULTIPLY); + rect_for_octives.x = OCTIVE_POSITION_X; + rect_for_octives.y = OCTIVE_POSITION_Y; + + texture_key_blank = SDL_CreateTextureFromSurface(renderer_for_piano, + surface_key_blank); + + if (texture_key_blank == NULL) { + printf("cannot texture keyboard blank keymap file\n"); + printf("%s\n", SDL_GetError()); + printf("\n"); + exit (0); + } + + texture_octive_blank = SDL_CreateTextureFromSurface(renderer_for_piano, + surface_octive_blank); + + if (texture_octive_blank == NULL) { + printf("cannot texture octive blank keymap file\n"); + printf("%s\n", SDL_GetError()); + printf("\n"); + exit (0); + } + + // do rest of keys and octives + // keys + for (loop_counter = 0; loop_counter < NUMBER_KEY_LIGHTS; loop_counter += 1) + { + surface_keys[loop_counter] = SDL_LoadBMP(keyboard_lights[loop_counter]); + + if (surface_keys[loop_counter] == NULL) { + printf("cannot load light file keymap file %s\n", keyboard_lights[loop_counter]); + printf("%s\n",SDL_GetError()); + printf("\n"); + exit (0); + } + + texture_keys[loop_counter] = SDL_CreateTextureFromSurface(renderer_for_piano, + surface_keys[loop_counter]); + + if (texture_keys[loop_counter] == NULL) { + printf("cannot texture keyboard light %d\n", loop_counter); + printf("%s\n", SDL_GetError()); + printf("\n"); + exit (0); + } + } + + // octives + for (loop_counter = 0; loop_counter < NUMBER_OCTIVE_LIGHTS; loop_counter += 1) + { + surface_octives[loop_counter] = SDL_LoadBMP(octive_lights[loop_counter]); + + if (surface_octives[loop_counter] == NULL) { + printf("cannot load light file octive file %s\n", octive_lights[loop_counter]); + printf("%s\n",SDL_GetError()); + printf("\n"); + exit (0); + } + + texture_octives[loop_counter] = SDL_CreateTextureFromSurface(renderer_for_piano, + surface_octives[loop_counter]); + + if (texture_octives[loop_counter] == NULL) { + printf("cannot texture octive light %d\n", loop_counter); + printf("%s\n", SDL_GetError()); + printf("\n"); + exit (0); + } + } + + + + // Put stuff on screen + + SDL_SetRenderDrawColor(renderer_for_piano, (Uint8)40, (Uint8)40, (Uint8)0, (Uint8)255); + + SDL_RenderClear(renderer_for_piano); + // SDL_RenderCopy(renderer_for_piano, texture_for_piano, NULL, &rect_for_piano_text); + SDL_RenderCopy(renderer_for_piano, texture_key_blank, NULL, &rect_for_keys); + SDL_RenderCopy(renderer_for_piano, texture_octive_blank, NULL, &rect_for_octives); + + SDL_RenderPresent(renderer_for_piano); + } diff --git a/piano_process.cpp b/piano_process.cpp new file mode 100644 index 0000000..fd6b3af --- /dev/null +++ b/piano_process.cpp @@ -0,0 +1,305 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "scope.h" + +// Functions to try to process Constant Q transform +piano_process_class::piano_process_class() + { + } + +piano_process_class::~piano_process_class() + { + } + +double piano_process_class::goertzel(int num_samples, int target_frequency, int sample_rate, + Sint16 *input_buffer) + { + double dinput_buffer; + double magnatude; + int k, i; + double doublenumsamples; + double omega, sine, cosine, coeff, q0, q1, q2, real, imag; + double scalingfactor; + + // Initialize constant stuff + + doublenumsamples = (double)num_samples; + scalingfactor = doublenumsamples / 2.0; + k = (int)(0.5 + ((doublenumsamples * (double)(target_frequency)) / (double)sample_rate)); + omega = (2.0 * M_PI * (double)k) / doublenumsamples; + sine = sin(omega); + cosine= cos(omega); + coeff = 2.0 * cosine; + + // Init q's + q0 = 0; + q1 = 0; + q2 = 0; + + + // First stage (2nd order IIR filter) + for (i = 0; i < num_samples; i += 1) + { + dinput_buffer = (double)*(input_buffer + i); + q2 = q1; + q1 = q0; + q0 = coeff * q1 - q2 + dinput_buffer; +// printf("q0 %f; dinput_buffer %f: integer_input_buffer %d\n", q0, dinput_buffer, *(input_buffer + i)); + } + + // Seconod stage (FIR filter) + real = (q0 - q1 *cosine) / scalingfactor; + imag = (-q1 * sine) / scalingfactor; + magnatude = sqrt((real * real) + (imag * imag)); + + + // Test Prints + + // printf("doublesamples %f; scalingfactor %f; k %d\n", doublenumsamples, scalingfactor, k); + // printf("omega %f; sine %f; cosine %f; coeff %f\n", omega, sine, cosine, coeff); + // printf("magnatude %f\n", magnatude); + + // printf("goertzel done\n"); + return magnatude; + } + +struct piano_data_struct *piano_process_class::process_piano_data(Sint16 *input_buffer) + { + int bucket_counter; + bucket_data_struct *current_bucket; + FILE *result_plot_file; + FILE *input_waveform_file; + FILE *note_result_plot_file; + Sint16 *current_read_buffer_in; + Sint16 *current_read_buffer_out; + int print_file_counter; + int count_for_transfering_buffers; + struct piano_note_struct *working_note; + struct piano_note_struct *strongest_note; + int note_counter; + + + // Before doing anything, we need to 1) update the full size buffer + // and ensure that it is full before processing, + // Otherwize return NULL if not. + + if (main_buffer_read_count < FFT_NUMBER_READ_BUFFERS) + { + current_read_buffer_in = input_buffer; + current_read_buffer_out = full_size_buffer + READ_BUFFER_SIZE * main_buffer_read_count; + for (count_for_transfering_buffers = 0; count_for_transfering_buffers < READ_BUFFER_SIZE; + count_for_transfering_buffers += 1) + { + *current_read_buffer_out = *current_read_buffer_in; + current_read_buffer_out += 1; + current_read_buffer_in += 1; + } + + main_buffer_read_count += 1; + return NULL; + } + else + { + main_buffer_read_count = 0; + } + + input_waveform_file = fopen("waveform_of_input","w"); + if (input_waveform_file == NULL) + { + printf("cant open input waveform_file\n"); + exit (0); + } + + for (print_file_counter = 0; print_file_counter < READ_BUFFER_SIZE * FFT_NUMBER_READ_BUFFERS; + print_file_counter += 2) + { + fprintf(input_waveform_file, "%d %d\n", print_file_counter, *(full_size_buffer + print_file_counter)); + // printf("%d %f\n", print_file_counter, (double)*(full_size_buffer + print_file_counter)); + } + + fclose (input_waveform_file); + + // Go through all of the buckets to get their strenght using Goertzel + // Test plotfile + result_plot_file = fopen("result_data_for_gnuplot", "w"); + if (result_plot_file == NULL) + { + printf("oops cant open result file\n"); + perror("cant open file\n"); + exit(0); + } + + note_result_plot_file = fopen("note_data_for_gnuplot", "w"); + if (note_result_plot_file == NULL) + { + printf("oops cant open note result file\n"); + perror("cant open file\n"); + exit(0); + } + + //clear the strengh in all notes + working_note = my_piano_notes; + for (note_counter = 0; note_counter < TOTAL_NOTES; note_counter += 1) + { + (working_note + note_counter)->note_strength = (double)0.0; + } + + for (bucket_counter = 0; bucket_counter < TOTAL_BUCKETS; bucket_counter += 1) + { + current_bucket = my_bucket_data + bucket_counter; + current_bucket->bucket_strength = goertzel(current_bucket->buffer_size, + current_bucket->bucket_frequency, + SAMPLE_RATE, + full_size_buffer); + current_bucket->this_piano_note->note_strength += current_bucket->bucket_strength; + + //Test print + fprintf(result_plot_file, + "%d %f\n", + bucket_counter, current_bucket->bucket_strength); + } + + working_note = my_piano_notes; + for (note_counter = 0; note_counter < TOTAL_NOTES; note_counter += 1) + { + fprintf(note_result_plot_file, "%d %f\n", note_counter, (working_note + note_counter)->note_strength); + } + + fclose (note_result_plot_file); + + //now find the strongest note + strongest_note = my_piano_notes; + working_note = my_piano_notes; + + for (note_counter = 0; note_counter < TOTAL_NOTES; note_counter += 1) + { + if (working_note->note_strength > strongest_note->note_strength) + { + strongest_note = working_note; + } + working_note += 1; + } + my_piano_data_struct.keyboard_key = strongest_note->keyboard_key; + my_piano_data_struct.octive = strongest_note->octive; + my_piano_data_struct.done = 1; + + + fclose (result_plot_file); + + // printf ("done process \n"); + return &my_piano_data_struct; + } + +int piano_process_class::initialize_piano_data() + { + double current_bucket_frequency; + double previous_bucket_frequency; + int current_octive; + int current_bucket; + int current_note; + int bucket_in_note; + int note_in_octive; + double semi_interval; + struct bucket_data_struct *current_bucket_pointer; + struct piano_note_struct *current_note_pointer; + FILE *print_records; + int array_counter; + + note_in_octive = 0; + current_bucket_frequency = (double)32.0; + previous_bucket_frequency = (double)32.0; + current_note = 0; + current_octive = 0; + bucket_in_note = 0; + + semi_interval = (double)(pow(2.0, 1.0/(double(BUCKETS_PER_OCTIVE)))); + + // printf("semi is %f\n", semi_interval); + + print_records = fopen("my_bucket_record","w"); + if (print_records == NULL) + { + printf ("cannot open records file \n"); + } + + // initialize full_size_buffer + for (array_counter = 0; array_counter < PIANO_FULL_ARRAY_SIZE; array_counter += 1) + { + full_size_buffer[array_counter] = (Sint16)0; + } + + main_buffer_read_count = 0; + + for (current_bucket = 0; current_bucket < TOTAL_BUCKETS; current_bucket += 1) + { + // Set pointers to bucket structure + current_bucket_pointer = my_bucket_data + current_bucket; + // Set pointer to note + current_note_pointer = my_piano_notes + (int)(current_bucket / BUCKETS_PER_NOTE) + bucket_in_note; + // Fill out both bucket and note structures + current_bucket_pointer->this_piano_note = current_note_pointer; + current_bucket_pointer->bucket_strength = 0.0; + current_note_pointer->note_strength = 0.0; + current_note_pointer->keyboard_key = note_in_octive; + current_note_pointer->octive = current_octive; + + //Set current bucket frequency + //First is handled differently + if (current_bucket == 0) + { + current_bucket_pointer->bucket_frequency = current_bucket_frequency; + previous_bucket_frequency = current_bucket_frequency; + } + + else + { + current_bucket_frequency = previous_bucket_frequency * semi_interval; + previous_bucket_frequency = current_bucket_frequency; + } + + current_bucket_pointer->bucket_frequency = current_bucket_frequency; + + // Radians on cycle per sample + current_bucket_pointer->radians_per_sample = (double)RADIANS_PER_SAMPLE_AT_1_HZ * + (double)current_bucket_pointer->bucket_frequency; + + // Buffer size for this bucket's frequency + current_bucket_pointer->buffer_size = (int)((double)(SAMPLE_RATE)/ + current_bucket_pointer->bucket_frequency) * Q_QUALITY; + + //Verification prints + fprintf (print_records, "current bucket - %d; bucket in note - %d; note in octive - %d; current note %d; current octive - %d ; bucket_frequency - %f ; degree per sample - %f; buffer size - %d; which note - %d\n", + current_bucket, bucket_in_note, note_in_octive, current_note, current_octive, + current_bucket_pointer->bucket_frequency, current_bucket_pointer->radians_per_sample, + current_bucket_pointer->buffer_size, + (int)(current_bucket / BUCKETS_PER_NOTE)); + + // Bump up for next; reset if necessary + // Note frequency + + // Update bucket in note and note in octive + bucket_in_note += 1; + if (bucket_in_note == BUCKETS_PER_NOTE) + { + bucket_in_note = 0; + current_note += 1; + note_in_octive += 1; + if (note_in_octive == NOTES_PER_OCTIVE) + { + note_in_octive = 0; + current_octive += 1; + } + } + } + + fclose(print_records); + printf ("done initialize \n"); + return 0; + } + diff --git a/scope.cpp b/scope.cpp new file mode 100644 index 0000000..cd0fb50 --- /dev/null +++ b/scope.cpp @@ -0,0 +1,204 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scope.h" + +// Main window size (location is 0, 0) +int x_window_size = 0; +int y_window_size = 0; +char input_our_audio_device_name[100]; + +main_window_class *my_main_window = NULL; +audio_window_class *my_audio_window = NULL; +spectrum_window_class *my_spectrum_window = NULL; +piano_window_class *my_piano_window = NULL; +main_buffer_manager_class *my_main_buffer_manager = NULL; +audio_buffer_manager_class *my_audio_buffer_manager = NULL; +spectrum_buffer_manager_class *my_spectrum_buffer_manager = NULL; +piano_process_class *my_piano_process = NULL; + +struct piano_data_struct *piano_data_pointer=NULL; + +Uint64 last_time; +Uint64 this_time; + +// SDL Event to stop application on pressing a key on the keyboard +SDL_Event my_event; +int get_me_out = 0; + +int main(int argc, char *argv[]) +{ + + // function result + int main_function_result = 0; + + // Get parameters for size + if (argc < 3) + { + printf ("needs x and y size \n"); + exit (0); + } + + x_window_size = atoi(argv[1]); + y_window_size = atoi(argv[2]); + + int our_audio_trace_width; + int our_audio_trace_height; + int our_spectrum_trace_width; + int our_spectrum_trace_height; + + Sint16 *my_main_buffer; + int *return_audio_buffer; + int *return_spectrum_buffer; + + printf ("window is %d by %d\n", x_window_size, y_window_size); + + // returns zero on success else non-zero + if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { + printf("error initializing SDL: %s\n", SDL_GetError()); + } + + // returns zero on success else non-zero + + if (TTF_Init() != 0 ){ + printf("error initializing TTF: %s\n", SDL_GetError()); + } + + // Windows + my_main_window = new main_window_class(x_window_size, y_window_size); + my_audio_window = new audio_window_class(x_window_size, y_window_size); + my_spectrum_window = new spectrum_window_class(x_window_size, y_window_size); + my_piano_window = new piano_window_class(x_window_size, y_window_size); + + // main buffer + my_main_buffer_manager = new main_buffer_manager_class(); + + // audio_buffer + my_audio_buffer_manager = new audio_buffer_manager_class(); + + // spectrum buffer + my_spectrum_buffer_manager = new spectrum_buffer_manager_class(); + + // piano_process + my_piano_process = new piano_process_class(); + + // audio window width and height + our_audio_trace_width = my_audio_window->get_max_audio_trace_width(); + our_audio_trace_height = my_audio_window->get_max_audio_trace_height(); + + // spectrum window width and height + our_spectrum_trace_width = my_spectrum_window->get_max_spectrum_trace_width(); + our_spectrum_trace_height = my_spectrum_window->get_max_spectrum_trace_height(); + + // buffer initializations + my_main_buffer = my_main_buffer_manager->initial_preparation(); + if (my_main_buffer == NULL) + { + printf("error initialize main_buffer\n"); + exit (0); + } + + main_function_result = my_audio_buffer_manager->initialize_audio + (our_audio_trace_width, our_audio_trace_height, my_main_buffer); + if (main_function_result) + { + printf("error initialize audio_buffer\n"); + exit (0); + } + + main_function_result = my_spectrum_buffer_manager->initialize_spectrum + (our_spectrum_trace_width, our_spectrum_trace_height, my_main_buffer); + if (main_function_result) + { + printf("error initialize spectrum_buffer\n"); + exit (0); + } + + //Initialize Piano Data Processor + main_function_result = my_piano_process->initialize_piano_data(); + if (main_function_result) + { + printf("error initialize piano processing\n"); + exit (0); + } + + //Read and process and display loop + + last_time = 0; + + while (get_me_out == 0) { + + while(SDL_PollEvent(&my_event)) { + printf("got event event type is %d\n", my_event.type); + switch (my_event.type) { + case SDL_QUIT: get_me_out = 1; + case SDL_KEYDOWN: get_me_out = 1; + break; + } + } + // SDL_Delay(100); + + my_main_buffer = my_main_buffer_manager->read_main_buffer(); + if (my_main_buffer == NULL) + { + printf("error resding into main_buffer\n"); + exit (0); + } + + return_audio_buffer = my_audio_buffer_manager->process_audio(); + if (return_audio_buffer == NULL) + { + printf("error processing audio to return_audio_buffer\n"); + exit (0); + } + + return_spectrum_buffer = my_spectrum_buffer_manager->process_spectrum(); + + //gettimeofday(&stop_time, NULL); + //gettimeofday(&start_time, NULL); + + this_time = SDL_GetTicks64(); + if (this_time >= last_time) + { + while ((last_time + FRAME_TIME) > this_time) + { + usleep(1000); + this_time = SDL_GetTicks64(); + } + } + + last_time = this_time; + + main_function_result = my_audio_window->draw_trace(return_audio_buffer, + our_audio_trace_width); + + // display fft only when the entire fft buffer is done + if (return_spectrum_buffer != NULL) + { + main_function_result = my_spectrum_window->draw_trace(return_spectrum_buffer, + our_spectrum_trace_width); + } + + // Piano section + piano_data_pointer = my_piano_process->process_piano_data(my_main_buffer); + if (piano_data_pointer == NULL) + { + printf("piano not done\n"); + } + else + { + printf ("piano done\n"); + my_piano_window->draw_trace(piano_data_pointer); + } + } + + + return main_function_result; +} diff --git a/scope.h b/scope.h new file mode 100644 index 0000000..4dc1c44 --- /dev/null +++ b/scope.h @@ -0,0 +1,267 @@ +#ifndef SCOPE +#define SCOPE +#include +#include +#include + + +#define SAMPLE_RATE 44100 +#define FRAME_TIME 17 +// this must be in power of 2 for fourier transform +#define READ_BUFFER_SIZE 2048 +#define FFT_NUMBER_READ_BUFFERS 4 +#define FFT_BUFFER_SIZE (READ_BUFFER_SIZE * FFT_NUMBER_READ_BUFFERS) +#define MAIN_BUFFER_SIZE 8192 +#define AUDIO_BUFFER_SIZE 6000 +#define FFT_START_BUCKET 0 +#define MAIN_VOLUME .1 +#define SPECTRUM_VOLUME .1 +#define PIANO_SIZE_MULTIPLY .65 +#define KEYBOARD_POSITION_X 50 +#define KEYBOARD_POSITION_Y 10 +#define OCTIVE_POSITION_X 800 +#define OCTIVE_POSITION_Y 10 +#define NUMBER_KEY_LIGHTS 12 +#define NUMBER_OCTIVE_LIGHTS 8 +#define RADIANS_PER_SAMPLE_AT_1_HZ (double)6.28319/(double)SAMPLE_RATE +#define NUMBER_OCTIVES 6 +#define BUCKETS_PER_NOTE 2 +#define NOTES_PER_OCTIVE 12 +#define BUCKETS_PER_OCTIVE BUCKETS_PER_NOTE*NOTES_PER_OCTIVE +#define TOTAL_BUCKETS BUCKETS_PER_OCTIVE*NUMBER_OCTIVES +#define TOTAL_NOTES NOTES_PER_OCTIVE*NUMBER_OCTIVES +#define Q_QUALITY 6 +#define FIRST_FREQUENCY 32 +#define PIANO_FULL_ARRAY_SIZE 10000 + +//Structure for piano notes +struct piano_note_struct { +double note_strength; +int keyboard_key; +int octive;; +}; + +//Structure for processing buckets +struct bucket_data_struct { +double bucket_frequency; +double bucket_strength; +int buffer_size; +double radians_per_sample; +struct piano_note_struct *this_piano_note; +}; + +// Structure used by both piano and main classes +struct piano_data_struct { +int keyboard_key; +int octive; +int done; +}; + +class main_window_class { + public: + main_window_class (int x_main_window_size, int y_main_window_size); + + private: + SDL_Window *window_for_main; + SDL_Renderer *renderer_for_main; + int call_result; + +}; + +class audio_window_class { + + public: + audio_window_class (int x_main_window_size, int y_main_window_size); + int draw_trace(int *audio_data, int audio_data_size); + int get_max_audio_trace_width(); + int get_max_audio_trace_height(); + + private: + int x_audio_window_position; + int y_audio_window_position; + int x_audio_window_size; + int y_audio_window_size; + int x_audio_window_trace_base; + int y_audio_window_trace_base; + int max_audio_trace_width; + int max_audio_trace_height; + SDL_Window *window_for_audio; + SDL_Renderer *renderer_for_audio; + SDL_Rect rect_for_audio; + SDL_Texture *texture_for_audio; + SDL_Surface *surface_for_audio; + TTF_Font *font_for_audio; + SDL_Color color_for_audio; +}; + +class spectrum_window_class { + + public: + spectrum_window_class (int x_main_window_size, int y_main_window_size); + int draw_trace(int *spectrum_data, int spectrum_data_size); + int get_max_spectrum_trace_width(); + int get_max_spectrum_trace_height(); + + private: + int x_spectrum_window_position; + int y_spectrum_window_position; + int x_spectrum_window_size; + int y_spectrum_window_size; + int x_spectrum_window_trace_base; + int y_spectrum_window_trace_base; + int max_spectrum_trace_width; + int max_spectrum_trace_height; + SDL_Window *window_for_spectrum; + SDL_Renderer *renderer_for_spectrum; + SDL_Rect rect_for_spectrum; + SDL_Texture *texture_for_spectrum; + SDL_Surface *surface_for_spectrum; + TTF_Font *font_for_spectrum; + SDL_Color color_for_spectrum; +}; + +class piano_window_class { + + public: + piano_window_class (int x_main_window_size, int y_main_window_size); + int draw_trace(piano_data_struct *input_piano_data); + int get_max_piano_trace_width(); + int get_max_piano_trace_height(); + + private: + const char* keyboard_lights[12] = { + "/home/maallyn/sound-scope/sdl2/fft/keyboard-key1.bmp", + "/home/maallyn/sound-scope/sdl2/fft/keyboard-key2.bmp", + "/home/maallyn/sound-scope/sdl2/fft/keyboard-key3.bmp", + "/home/maallyn/sound-scope/sdl2/fft/keyboard-key4.bmp", + "/home/maallyn/sound-scope/sdl2/fft/keyboard-key5.bmp", + "/home/maallyn/sound-scope/sdl2/fft/keyboard-key6.bmp", + "/home/maallyn/sound-scope/sdl2/fft/keyboard-key7.bmp", + "/home/maallyn/sound-scope/sdl2/fft/keyboard-key8.bmp", + "/home/maallyn/sound-scope/sdl2/fft/keyboard-key9.bmp", + "/home/maallyn/sound-scope/sdl2/fft/keyboard-key10.bmp", + "/home/maallyn/sound-scope/sdl2/fft/keyboard-key11.bmp", + "/home/maallyn/sound-scope/sdl2/fft/keyboard-key12.bmp"}; + + const char* octive_lights[8] = { + "/home/maallyn/sound-scope/sdl2/fft/octive-1.bmp", + "/home/maallyn/sound-scope/sdl2/fft/octive-2.bmp", + "/home/maallyn/sound-scope/sdl2/fft/octive-3.bmp", + "/home/maallyn/sound-scope/sdl2/fft/octive-4.bmp", + "/home/maallyn/sound-scope/sdl2/fft/octive-5.bmp", + "/home/maallyn/sound-scope/sdl2/fft/octive-6.bmp", + "/home/maallyn/sound-scope/sdl2/fft/octive-7.bmp", + "/home/maallyn/sound-scope/sdl2/fft/octive-8.bmp"}; + + struct piano_data_struct *my_piano_data; + int x_piano_window_position; + int y_piano_window_position; + int x_piano_window_size; + int y_piano_window_size; + int x_piano_window_trace_base; + int y_piano_window_trace_base; + int max_piano_trace_width; + int max_piano_trace_height; + int function_result; + int loop_counter; + SDL_Window *window_for_piano; + SDL_Renderer *renderer_for_piano; + SDL_Rect rect_for_piano_text; + SDL_Texture *texture_for_piano; + SDL_Surface *surface_for_piano_text; + SDL_Surface *surface_key_blank; + SDL_Surface *surface_keys[12]; + SDL_Surface *surface_octive_blank; + SDL_Surface *surface_octives[8]; + SDL_Texture *texture_key_blank; + SDL_Texture *texture_keys[12]; + SDL_Texture *texture_octive_blank; + SDL_Texture *texture_octives[8]; + SDL_Texture *texture_current_piano_light; + SDL_Texture *texture_current_octive_light; + SDL_Rect rect_for_keys; + SDL_Rect rect_for_octives; + + TTF_Font *font_for_piano; + SDL_Color color_for_piano; + SDL_Rect rect_for_piano_image; + SDL_Surface *piano_image_surface; + SDL_Texture *texture_of_piano_image; +}; + +class main_buffer_manager_class { + public: + main_buffer_manager_class(); + ~main_buffer_manager_class(); + Sint16 *initial_preparation(); + Sint16 *read_main_buffer(); + + private: + Sint16 *my_read_main_buffer; + int pulse_error; + int function_return; + pa_simple *pulse_s = NULL; + int main_buffer_index; + Sint16 main_buffer_hold; + }; + +class audio_buffer_manager_class { + public: + audio_buffer_manager_class(); + ~audio_buffer_manager_class(); + int initialize_audio(int horizontal_size,int vertical_size, Sint16 *main_buffer); + int *process_audio(); + + private: + Sint16 *my_main_buffer; + int *my_formatted_audio_buffer; + int my_audio_horizontal_size; + int my_audio_vertical_size; + int my_read_audio_index; + int function_return; + Sint16 audio_holding; + }; + +class spectrum_buffer_manager_class { + public: + spectrum_buffer_manager_class(); + ~spectrum_buffer_manager_class(); + int initialize_spectrum(int horizontal_size,int vertical_size, Sint16 *main_buffer); + int *process_spectrum(); + + private: + Sint16 *my_main_buffer; + int *my_formatted_spectrum_buffer; + int my_spectrum_horizontal_size; + int my_spectrum_vertical_size; + int my_read_spectrum_index; + int my_output_fft_buffer_index; + int function_return; + int read_buffer_counter; + Sint16 spectrum_holding; + fftw_plan my_fftw_plan; + double *input_fftw; + double *input_fftw_write_position; + Sint16 main_buffer_hold; + fftw_complex *output_fftw; + }; + +class piano_process_class { + public: + piano_process_class(); + ~piano_process_class(); + int initialize_piano_data(); + struct piano_data_struct *process_piano_data(Sint16 *input_buffer); + double goertzel(int num_samples, int target_frequency, int sample_rate, Sint16 *input_buffer); + + private: + struct piano_data_struct my_piano_data_struct; + Sint16 *local_main_buffer; + int ctr1; + struct piano_note_struct my_piano_notes[TOTAL_NOTES]; + struct bucket_data_struct my_bucket_data[TOTAL_BUCKETS]; + Sint16 full_size_buffer[PIANO_FULL_ARRAY_SIZE]; + int main_buffer_read_count; + + }; +#endif diff --git a/sized-piano-keys.png b/sized-piano-keys.png new file mode 100755 index 0000000..d2fd7f8 Binary files /dev/null and b/sized-piano-keys.png differ diff --git a/spectrum_buffer_manager_class.cpp b/spectrum_buffer_manager_class.cpp new file mode 100644 index 0000000..428ee20 --- /dev/null +++ b/spectrum_buffer_manager_class.cpp @@ -0,0 +1,137 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scope.h" + +spectrum_buffer_manager_class::spectrum_buffer_manager_class() + { + my_formatted_spectrum_buffer = NULL; + } + +spectrum_buffer_manager_class::~spectrum_buffer_manager_class() + { + if (my_formatted_spectrum_buffer != NULL) + { + free(my_formatted_spectrum_buffer); + } + } + +int spectrum_buffer_manager_class::initialize_spectrum(int horizontal_size, + int vertical_size, Sint16 *main_buffer) + { + // This is the formatted buffer that will be fed to the display + my_formatted_spectrum_buffer = (int *)malloc ((sizeof(int) * AUDIO_BUFFER_SIZE)); + if (my_formatted_spectrum_buffer == NULL) + { + printf ("cannot allocate formatted spectrum spectrum buffer\n"); + perror ("error is"); + return 1; + } + + //Allocate output fftw buffer + if ((output_fftw = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) + * FFT_BUFFER_SIZE * 2)) == NULL) + { + printf ("cannot allocate fftw output buffer\n"); + perror ("error is"); + return 1; + } + + //Allocate input fftw buffer + if ((input_fftw = (double*) fftw_malloc(sizeof(double) * FFT_BUFFER_SIZE)) == NULL) + { + printf ("cannot allocate fftw input buffer\n"); + perror ("error is"); + return 1; + } + + // Now lets attempt to perform an fftw plan + if ((my_fftw_plan = fftw_plan_dft_r2c_1d(FFT_BUFFER_SIZE, input_fftw, + output_fftw, FFTW_MEASURE)) == NULL) + { + printf ("cannot fftw plan"); + perror ("error is"); + return 1; + } + + // my_read_spectrum_index is which chunk we will put the read buffer into + my_read_spectrum_index = 0; + + // index to read the individual elements into the fftw input buffer + read_buffer_counter = 0; + + // my_output_fft_buffer_index is used to flip output buffer + // members all to negative for display purposes + + my_output_fft_buffer_index = 0; + + my_spectrum_horizontal_size = horizontal_size; + my_spectrum_vertical_size = vertical_size; + + // The main buffer is the read buffer from main buffer read + my_main_buffer = main_buffer; + return 0; + } + +// Returns address for formatted fft buffer for ready to display +// Return NULL for waiting for buffer fill +int *spectrum_buffer_manager_class::process_spectrum() + { + // Fill the fftw input array + // Fill in section corresponging to the current read_buffer_counter + input_fftw_write_position = input_fftw + my_read_spectrum_index; + for (read_buffer_counter = 0; read_buffer_counter < READ_BUFFER_SIZE; + read_buffer_counter += 1) + { + main_buffer_hold = (Sint16)(*(my_main_buffer + read_buffer_counter) * SPECTRUM_VOLUME); + *(input_fftw_write_position + read_buffer_counter) = (double)main_buffer_hold; + } + + /* prep for next time */ + my_read_spectrum_index += 1; + // Are we still working on filling this buffer? + if (my_read_spectrum_index < FFT_NUMBER_READ_BUFFERS) + { + // Lets wait + return NULL; + } + else + // Done filling up fft buffer - lets process + { + // First, reset the spectrum index to 0 + my_read_spectrum_index = 0; + + // Perform the fft + fftw_execute(my_fftw_plan); + + // Now grab the real part of the complex output + for (my_output_fft_buffer_index = 0; + my_output_fft_buffer_index < my_spectrum_horizontal_size; + my_output_fft_buffer_index += 1) + { + *(my_formatted_spectrum_buffer + my_output_fft_buffer_index) + = (int)(output_fftw[(FFT_START_BUCKET + + (my_output_fft_buffer_index))][0] * SPECTRUM_VOLUME); + if (*(my_formatted_spectrum_buffer + my_output_fft_buffer_index) > 0 ) + { + // Flip any positive values to negative because negative causes location + // to go up on the sdl coordinate system + *(my_formatted_spectrum_buffer + my_output_fft_buffer_index) = + - *(my_formatted_spectrum_buffer + my_output_fft_buffer_index); + } + } + } + + return my_formatted_spectrum_buffer; + } + diff --git a/spectrum_class.cpp b/spectrum_class.cpp new file mode 100644 index 0000000..e5b6bf1 --- /dev/null +++ b/spectrum_class.cpp @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "scope.h" + +// Spectrum class method bodies +// Spectrum window + +int spectrum_window_class::draw_trace(int *spectrum_data, int spectrum_data_size) + { + int spectrum_data_counter; + int *current_spectrum_data_value; + int *prev_spectrum_data_value; + int this_spectrum_data_size; + + if (spectrum_data_size >= max_spectrum_trace_width) + { + this_spectrum_data_size = max_spectrum_trace_width; + } + else + { + this_spectrum_data_size = spectrum_data_size; + } + + //printf("this size %d\n", this_spectrum_data_size); + //Clear the window + SDL_SetRenderDrawColor(renderer_for_spectrum, (Uint8)40, (Uint8)40, (Uint8)0, (Uint8)255); + SDL_RenderClear(renderer_for_spectrum); + + // Render word Spectrum + SDL_RenderCopy(renderer_for_spectrum, texture_for_spectrum, NULL, &rect_for_spectrum); + + // green trace + SDL_SetRenderDrawColor(renderer_for_spectrum, (Uint8)0, (Uint8)(255), (Uint8)255, (Uint8)255); + + for (spectrum_data_counter = 1; spectrum_data_counter < this_spectrum_data_size; spectrum_data_counter += 1) + { + current_spectrum_data_value = spectrum_data + spectrum_data_counter; + prev_spectrum_data_value = spectrum_data + spectrum_data_counter - 1; + SDL_RenderDrawLine (renderer_for_spectrum, x_spectrum_window_trace_base + spectrum_data_counter -1, + y_spectrum_window_trace_base + *prev_spectrum_data_value, + x_spectrum_window_trace_base + spectrum_data_counter, + y_spectrum_window_trace_base + *current_spectrum_data_value); + } + + SDL_RenderPresent(renderer_for_spectrum); + return 0; + } + +int spectrum_window_class::get_max_spectrum_trace_width() + { + return max_spectrum_trace_width; + } + +int spectrum_window_class::get_max_spectrum_trace_height() + { + return max_spectrum_trace_height; + } + + +spectrum_window_class::spectrum_window_class (int x_main_window_size, int y_main_window_size) + { + x_spectrum_window_position = 30 + (int)(x_main_window_size / 2); + y_spectrum_window_position = 5; + x_spectrum_window_size = ((int)(x_main_window_size / 2)) - 10; + y_spectrum_window_size = (((int)(y_main_window_size / 3)) * 2) - 10; + x_spectrum_window_trace_base = 1; + y_spectrum_window_trace_base = y_spectrum_window_size - 2; + max_spectrum_trace_width = x_spectrum_window_size - 2; + max_spectrum_trace_height = y_spectrum_window_size; + if ((window_for_spectrum = SDL_CreateWindow("Spectrum", + x_spectrum_window_position, y_spectrum_window_position, + x_spectrum_window_size, y_spectrum_window_size,0)) == NULL) { + printf("error opening spectrum window SDL: %s\n", SDL_GetError()); + exit (0); + } + + printf("spectrum window: window_size %d x pos %d max trace width %d\n", + x_spectrum_window_size, x_spectrum_window_position, max_spectrum_trace_width); + + SDL_SetWindowBordered(window_for_spectrum, SDL_FALSE); + + if ((renderer_for_spectrum = SDL_CreateRenderer(window_for_spectrum, -1, 0)) == NULL) { + printf("error opening spectrum renderer SDL: %s\n", SDL_GetError()); + exit (0); + } + + if ((font_for_spectrum = TTF_OpenFont("/usr/share/fonts/truetype/freefont/FreeSans.ttf", + 24)) == NULL) { + printf("error opening spectrum font SDL: %s\n", SDL_GetError()); + exit (0); + } + + color_for_spectrum = {255,255,255}; + + if ((surface_for_spectrum = TTF_RenderText_Solid(font_for_spectrum, + "SPECTRUM ANALYZER", color_for_spectrum)) == NULL) { + printf("error opening spectrum surface SDL: %s\n", SDL_GetError()); + exit (0); + } + + + if ((texture_for_spectrum = SDL_CreateTextureFromSurface(renderer_for_spectrum, + surface_for_spectrum)) == NULL) { + printf("error opening spectrum texture SDL: %s\n", SDL_GetError()); + exit (0); + } + + rect_for_spectrum.x = x_spectrum_window_trace_base + ((int)(max_spectrum_trace_width/2) - + (int)(surface_for_spectrum->w / 2)); + rect_for_spectrum.y = 20; + rect_for_spectrum.w = surface_for_spectrum->w; + rect_for_spectrum.h = surface_for_spectrum->h; + + SDL_SetRenderDrawColor(renderer_for_spectrum, (Uint8)40, (Uint8)40, (Uint8)0, (Uint8)255); + + SDL_RenderClear(renderer_for_spectrum); + SDL_RenderCopy(renderer_for_spectrum, texture_for_spectrum, NULL, &rect_for_spectrum); + + SDL_RenderPresent(renderer_for_spectrum); + }