aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksa Vuckovic <aleksa@vuckovic.cc>2023-11-18 22:12:55 +0100
committerAleksa Vuckovic <aleksa@vuckovic.cc>2023-11-18 22:18:21 +0100
commitfba043f4234453f68284cb31d8c215ff5af6a66f (patch)
tree0b35c94ceefc55bb7beb76af6d065bf335e9baa5
parent45d8de6c22a51efe7e76e71424693c18b93e83e3 (diff)
RefactoringHEADmaster
-rw-r--r--.ccls1
-rw-r--r--.clang-format2
-rw-r--r--Makefile6
-rw-r--r--lib/audio.hpp28
-rw-r--r--lib/ui.hpp36
-rw-r--r--src/audio.cpp82
-rw-r--r--src/main.c195
-rw-r--r--src/main.cpp7
-rw-r--r--src/ui.cpp162
9 files changed, 321 insertions, 198 deletions
diff --git a/.ccls b/.ccls
index f1af59a..aec96cd 100644
--- a/.ccls
+++ b/.ccls
@@ -1,4 +1,5 @@
clang
+-Ilib
-I/usr/include/cairo
-I/usr/include/libpng16
-I/usr/include/freetype2
diff --git a/.clang-format b/.clang-format
index edb18e6..52768d3 100644
--- a/.clang-format
+++ b/.clang-format
@@ -508,7 +508,7 @@ PenaltyBreakString: 10
PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 60
-PointerAlignment: Right
+PointerAlignment: Left
ReflowComments: false
SortIncludes: false
#SortUsingDeclarations: false # Unknown to clang-format-4.0
diff --git a/Makefile b/Makefile
index 1a0c98d..1dce519 100644
--- a/Makefile
+++ b/Makefile
@@ -2,9 +2,11 @@ CXX=g++
CC=gcc
LDFLAGS=-lportaudio $(shell pkg-config --libs gtk4 cairo)
-CXXFLAGS=-Wall $(shell pkg-config --cflags gtk4 cairo) -O3 -MD -MP
+CXXFLAGS=-Wall -Ilib $(shell pkg-config --cflags gtk4 cairo) -O0 -g -MD -MP
OBJS=\
- src/main.o
+ src/audio.o \
+ src/main.o \
+ src/ui.o
.PHONY: all build run clean
diff --git a/lib/audio.hpp b/lib/audio.hpp
new file mode 100644
index 0000000..3502714
--- /dev/null
+++ b/lib/audio.hpp
@@ -0,0 +1,28 @@
+#ifndef AUDIO_HPP
+#define AUDIO_HPP
+
+#include <portaudio.h>
+
+#define FRAMES_PER_BUFFER 256
+
+class AudioData {
+ public:
+ AudioData();
+ void set_device_num(int device_num);
+ int get_channel_cnt();
+ float* get_channels();
+
+ void start_stream();
+ void close_stream();
+
+ private:
+ PaStream* stream;
+ int device_num;
+ int channel_cnt;
+ float* channels;
+
+ static int patestCallback(const void* inputBuffer, void* outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags,
+ void* userData);
+};
+
+#endif
diff --git a/lib/ui.hpp b/lib/ui.hpp
new file mode 100644
index 0000000..c656058
--- /dev/null
+++ b/lib/ui.hpp
@@ -0,0 +1,36 @@
+#ifndef UI_HPP
+#define UI_HPP
+
+#include <gtk/gtk.h>
+#include <cairo/cairo.h>
+#include "audio.hpp"
+#include <bits/stdc++.h>
+
+using namespace std;
+
+class GTKUI {
+ public:
+ GTKUI(int argc, char* argv[]);
+ static void draw(cairo_t* cr, GtkWidget* drawing_area, gpointer user_data);
+ static void draw_cb(GtkDrawingArea* drawing_area, cairo_t* cr, int width, int height, gpointer user_data);
+ static void select_device(GtkWidget* widget, gpointer user_data);
+ static void refresh(GtkWidget* widget, gpointer user_data);
+ static void close_window(GtkWidget* widget, gpointer user_data);
+ static gboolean drawCallback(GtkWidget* widget, GdkFrameClock* frame_clock, gpointer user_data);
+ static void activate(GtkApplication* app, gpointer user_data);
+
+ private:
+ GtkApplication* app;
+
+ GtkWidget* window;
+ GtkWidget* grid;
+ GtkWidget* refresh_button;
+ GtkWidget* quit_button;
+ vector<GtkWidget*> buttons;
+ GtkWidget* drawing_area;
+
+ int status;
+ AudioData* audiodata;
+};
+
+#endif
diff --git a/src/audio.cpp b/src/audio.cpp
new file mode 100644
index 0000000..e5aed56
--- /dev/null
+++ b/src/audio.cpp
@@ -0,0 +1,82 @@
+#include "audio.hpp"
+#include <bits/stdc++.h>
+
+using namespace std;
+
+AudioData::AudioData()
+{
+ this->device_num = 0;
+ this->channel_cnt = 0;
+ this->channels = NULL;
+ this->stream = NULL;
+}
+
+int AudioData::get_channel_cnt()
+{
+ return this->channel_cnt;
+}
+
+float* AudioData::get_channels()
+{
+ return this->channels;
+}
+
+void AudioData::set_device_num(int device_num)
+{
+ this->device_num = device_num;
+}
+
+int AudioData::patestCallback(const void* inputBuffer, void* outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void* userData)
+{
+ AudioData* data = (AudioData*)userData;
+ float* in = (float*)inputBuffer;
+
+ for (int i = 0; i < data->channel_cnt; i++) {
+ if (data->channels[i] > 0) {
+ data->channels[i] -= 0.005;
+ }
+ }
+
+ for (unsigned long i = 0; i < framesPerBuffer * data->channel_cnt; i += data->channel_cnt) {
+ for (int j = 0; j < data->channel_cnt; j++) {
+ data->channels[j] = max(data->channels[j], fabs(in[i + j]));
+ }
+ }
+
+ return 0;
+}
+
+void AudioData::start_stream()
+{
+ close_stream();
+ Pa_Initialize();
+
+ PaStreamParameters inputParameters;
+ memset(&inputParameters, 0, sizeof(inputParameters));
+ inputParameters.channelCount = Pa_GetDeviceInfo(device_num)->maxInputChannels;
+ inputParameters.device = device_num;
+ inputParameters.hostApiSpecificStreamInfo = NULL;
+ inputParameters.sampleFormat = paFloat32;
+ inputParameters.suggestedLatency = Pa_GetDeviceInfo(device_num)->defaultLowInputLatency;
+
+ this->channel_cnt = inputParameters.channelCount;
+ this->channels = (float*)calloc(this->channel_cnt, sizeof(float));
+
+ Pa_OpenStream(&stream, &inputParameters, NULL, Pa_GetDeviceInfo(device_num)->defaultSampleRate, FRAMES_PER_BUFFER, paNoFlag, &this->patestCallback, this);
+ Pa_StartStream(stream);
+}
+
+void AudioData::close_stream()
+{
+ if (this->stream != NULL) {
+ Pa_StopStream(this->stream);
+ Pa_CloseStream(this->stream);
+ Pa_Terminate();
+ this->stream = NULL;
+ }
+
+ if (this->channels) {
+ free(this->channels);
+ this->channels = NULL;
+ }
+}
diff --git a/src/main.c b/src/main.c
deleted file mode 100644
index 10d00eb..0000000
--- a/src/main.c
+++ /dev/null
@@ -1,195 +0,0 @@
-#include <gtk/gtk.h>
-#include <cairo/cairo.h>
-#include <portaudio.h>
-
-typedef struct {
- int device_num;
- int chanel_cnt;
- float *chanels;
-} AudioData;
-
-typedef struct {
- int device_num;
-} SelectedDevice;
-
-AudioData audiodata;
-PaStream *stream = NULL;
-GtkWidget *drawing_area;
-
-#define FRAMES_PER_BUFFER 256
-
-int patestCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
-{
- AudioData *data = (AudioData *)userData;
- float *in = (float *)inputBuffer;
-
- for (int i = 0; i < data->chanel_cnt; i++) {
- if (data->chanels[i] > 0) {
- data->chanels[i] -= 0.005;
- }
- }
-
- for (unsigned long i = 0; i < framesPerBuffer * data->chanel_cnt; i += data->chanel_cnt) {
- for (int j = 0; j < data->chanel_cnt; j++) {
- data->chanels[j] = MAX(data->chanels[j], fabs(in[i + j]));
- }
- }
-
- if (drawing_area) {
- gtk_widget_queue_draw(GTK_WIDGET(drawing_area));
- }
-
- return 0;
-}
-
-static void select_device(GtkWidget *widget, gpointer data)
-{
- if (stream != NULL) {
- Pa_StopStream(stream);
- Pa_CloseStream(stream);
- stream = NULL;
- }
-
- int device_num = ((SelectedDevice *)data)->device_num;
- printf("Device %d selected\n", device_num);
-
- PaStreamParameters inputParameters;
- memset(&inputParameters, 0, sizeof(inputParameters));
- inputParameters.channelCount = Pa_GetDeviceInfo(device_num)->maxInputChannels;
- inputParameters.device = device_num;
- inputParameters.hostApiSpecificStreamInfo = NULL;
- inputParameters.sampleFormat = paFloat32;
- inputParameters.suggestedLatency = Pa_GetDeviceInfo(device_num)->defaultLowInputLatency;
-
- audiodata.device_num = device_num;
- audiodata.chanel_cnt = inputParameters.channelCount;
- audiodata.chanels = (float *)calloc(audiodata.chanel_cnt, sizeof(float));
-
- Pa_OpenStream(&stream, &inputParameters, NULL, Pa_GetDeviceInfo(device_num)->defaultSampleRate, FRAMES_PER_BUFFER, paNoFlag, patestCallback, &audiodata);
- Pa_StartStream(stream);
-}
-
-static void draw(cairo_t *cr, GtkWidget *area)
-{
- float window_width = 900;
- float window_height = 900;
- float radius = 200;
- float space = 50;
- float delta, x, y;
-
- delta = 2 * M_PI / audiodata.chanel_cnt;
-
- cairo_set_source_rgba(cr, 1, 1, 1, 1);
- cairo_arc(cr, window_width / 2, window_height / 2, space, 0, 2 * M_PI);
- cairo_fill(cr);
-
- cairo_set_source_rgba(cr, 1, 0, 0, 1);
- for (int i = 0; i < audiodata.chanel_cnt; i += 2) {
- x = (radius + space) * cos(i * delta / 2);
- y = (radius + space) * sin(i * delta / 2);
-
- cairo_arc(cr, window_width / 2 - x, window_height / 2 - y, audiodata.chanels[i] * radius, 0, 2 * M_PI);
- cairo_arc(cr, window_width / 2 + x, window_height / 2 + y, audiodata.chanels[i + 1] * radius, 0, 2 * M_PI);
- }
- cairo_fill(cr);
-
- gtk_widget_queue_draw(area);
-}
-
-static void draw_cb(GtkDrawingArea *drawing_area, cairo_t *cr, int width, int height, gpointer data)
-{
- cairo_paint(cr);
- draw(cr, (GtkWidget *)data);
-}
-
-static void refresh(GtkWidget *grid)
-{
- Pa_Terminate();
- Pa_Initialize();
- int numDevices = Pa_GetDeviceCount();
-
- if (numDevices < 0) {
- printf("Error getting device count.\n");
- exit(EXIT_FAILURE);
- } else if (numDevices == 0) {
- printf("There are no available audio devices on this machine.\n");
- exit(EXIT_SUCCESS);
- }
-
- GtkWidget *button;
-
- for (int i = 0; i < numDevices; i++) {
- const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(i);
- SelectedDevice *sel_dev = (SelectedDevice *)malloc(sizeof(SelectedDevice));
- sel_dev->device_num = i;
- button = gtk_button_new_with_label(deviceInfo->name);
- g_signal_connect(button, "clicked", G_CALLBACK(select_device), sel_dev);
- gtk_grid_attach(GTK_GRID(grid), button, 0, numDevices - i - 1, 1, 1);
- }
-
- gtk_widget_queue_draw(grid);
-}
-
-static void close_window(GtkWindow *window)
-{
- if (stream != NULL) {
- Pa_StopStream(stream);
- Pa_CloseStream(stream);
- stream = NULL;
- }
-
- Pa_Terminate();
-
- gtk_window_destroy(window);
-}
-
-static void activate(GtkApplication *app, gpointer user_data)
-{
- GtkWidget *window;
- GtkWidget *grid;
- GtkWidget *button;
-
- // init window
- window = gtk_application_window_new(app);
- gtk_window_set_title(GTK_WINDOW(window), "Directional Audio Visualizer");
-
- // init grid
- grid = gtk_grid_new();
- gtk_window_set_child(GTK_WINDOW(window), grid);
-
- // init drawing_area
- drawing_area = gtk_drawing_area_new();
- gtk_widget_set_size_request(drawing_area, 900, 900);
- gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(drawing_area), draw_cb, drawing_area, NULL);
- gtk_grid_attach(GTK_GRID(grid), drawing_area, 1, 2, 100, 100);
-
- // init audio devices
- Pa_Initialize();
- refresh(grid);
-
- // init button for refresh
- button = gtk_button_new_with_label("Refresh");
- g_signal_connect_swapped(button, "clicked", G_CALLBACK(refresh), grid);
- gtk_grid_attach(GTK_GRID(grid), button, 1, 0, 1, 1);
-
- // init button for quit
- button = gtk_button_new_with_label("Quit");
- g_signal_connect_swapped(button, "clicked", G_CALLBACK(close_window), window);
- gtk_grid_attach(GTK_GRID(grid), button, 1, 1, 1, 1);
-
- // set window
- gtk_window_present(GTK_WINDOW(window));
-}
-
-int main(int argc, char **argv)
-{
- GtkApplication *app;
- int status;
-
- app = gtk_application_new("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS);
- g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
- status = g_application_run(G_APPLICATION(app), argc, argv);
- g_object_unref(app);
-
- return status;
-}
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..1c9a217
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,7 @@
+#include "audio.hpp"
+#include "ui.hpp"
+
+int main(int argc, char* argv[])
+{
+ GTKUI* gtk = new GTKUI(argc, argv);
+}
diff --git a/src/ui.cpp b/src/ui.cpp
new file mode 100644
index 0000000..a4b033b
--- /dev/null
+++ b/src/ui.cpp
@@ -0,0 +1,162 @@
+#include <bits/stdc++.h>
+#include "ui.hpp"
+
+using namespace std;
+
+void GTKUI::draw(cairo_t* cr, GtkWidget* drawing_area, gpointer user_data)
+{
+ GTKUI* gtk = (GTKUI*)user_data;
+ AudioData* audiodata = gtk->audiodata;
+
+ float window_width = 900;
+ float window_height = 900;
+ float radius = 200;
+ float space = 50;
+ float delta, x, y;
+
+ delta = 2 * M_PI / audiodata->get_channel_cnt();
+
+ cairo_set_source_rgba(cr, 1, 1, 1, 1);
+ cairo_arc(cr, window_width / 2, window_height / 2, space, 0, 2 * M_PI);
+ cairo_fill(cr);
+
+ cairo_set_source_rgba(cr, 1, 0, 0, 1);
+ for (int i = 0; i < audiodata->get_channel_cnt(); i += 2) {
+ x = (radius + space) * cos(i * delta / 2);
+ y = (radius + space) * sin(i * delta / 2);
+
+ cairo_arc(cr, window_width / 2 - x, window_height / 2 - y, audiodata->get_channels()[i] * radius, 0, 2 * M_PI);
+ cairo_arc(cr, window_width / 2 + x, window_height / 2 + y, audiodata->get_channels()[i + 1] * radius, 0, 2 * M_PI);
+ }
+ cairo_fill(cr);
+
+ gtk_widget_queue_draw(drawing_area);
+}
+
+void GTKUI::draw_cb(GtkDrawingArea* drawing_area, cairo_t* cr, int width, int height, gpointer user_data)
+{
+ GTKUI* gtk = (GTKUI*)user_data;
+ AudioData* audiodata = gtk->audiodata;
+
+ if (audiodata->get_channel_cnt() == 0)
+ return;
+
+ cairo_paint(cr);
+ draw(cr, GTK_WIDGET(drawing_area), user_data);
+}
+
+struct ButtonData {
+ GTKUI* gtk;
+ int select_device;
+};
+
+void GTKUI::select_device(GtkWidget* widget, gpointer user_data)
+{
+ ButtonData* buttond = (ButtonData*)user_data;
+ GTKUI* gtk = buttond->gtk;
+ AudioData* audiodata = gtk->audiodata;
+
+ audiodata->set_device_num(buttond->select_device);
+ audiodata->start_stream();
+
+ gtk_widget_add_tick_callback(gtk->drawing_area, gtk->drawCallback, user_data, NULL);
+}
+
+void GTKUI::refresh(GtkWidget* widget, gpointer user_data)
+{
+ GTKUI* gtk = (GTKUI*)user_data;
+ AudioData* audiodata = gtk->audiodata;
+
+ Pa_Terminate();
+ Pa_Initialize();
+
+ int numDevices = Pa_GetDeviceCount();
+
+ if (numDevices < 0) {
+ printf("Error getting device count.\n");
+ exit(EXIT_FAILURE);
+ } else if (numDevices == 0) {
+ printf("There are no available audio devices on this machine.\n");
+ exit(EXIT_SUCCESS);
+ }
+
+ GtkWidget* button;
+
+ for (int i = 0; i < numDevices; i++) {
+ const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo(i);
+
+ ButtonData* buttond = new ButtonData;
+ buttond->gtk = gtk;
+ buttond->select_device = i;
+
+ button = gtk_button_new_with_label(deviceInfo->name);
+ gtk->buttons.push_back(button);
+ g_signal_connect(button, "clicked", G_CALLBACK(select_device), buttond);
+ gtk_grid_attach(GTK_GRID(gtk->grid), button, 0, numDevices - i - 1, 1, 1);
+ }
+
+ gtk_widget_queue_draw(gtk->grid);
+}
+
+void GTKUI::close_window(GtkWidget* widget, gpointer user_data)
+{
+ GTKUI* gtk = (GTKUI*)user_data;
+ AudioData* audiodata = gtk->audiodata;
+
+ audiodata->close_stream();
+ gtk_window_destroy(GTK_WINDOW(gtk->window));
+}
+
+gboolean GTKUI::drawCallback(GtkWidget* widget, GdkFrameClock* frame_clock, gpointer user_data)
+{
+ if (widget) {
+ gtk_widget_queue_draw(GTK_WIDGET(widget));
+ }
+ return true;
+}
+
+void GTKUI::activate(GtkApplication* app, gpointer user_data)
+{
+ GTKUI* gtk = (GTKUI*)user_data;
+
+ // init window
+ gtk->window = gtk_application_window_new(app);
+ gtk_window_set_title(GTK_WINDOW(gtk->window), "Directional Audio Visualizer");
+
+ // init grid
+ gtk->grid = gtk_grid_new();
+ gtk_window_set_child(GTK_WINDOW(gtk->window), gtk->grid);
+
+ // init drawing_area
+ gtk->drawing_area = gtk_drawing_area_new();
+ gtk_widget_set_size_request(gtk->drawing_area, 900, 900);
+ gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(gtk->drawing_area), draw_cb, user_data, NULL);
+
+ gtk_grid_attach(GTK_GRID(gtk->grid), gtk->drawing_area, 1, 2, 100, 100);
+
+ // init audio devices
+ Pa_Initialize();
+ refresh(gtk->window, user_data);
+
+ // init button for refresh
+ gtk->refresh_button = gtk_button_new_with_label("Refresh");
+ g_signal_connect(gtk->refresh_button, "clicked", G_CALLBACK(gtk->refresh), gtk);
+ gtk_grid_attach(GTK_GRID(gtk->grid), gtk->refresh_button, 1, 0, 1, 1);
+
+ // init button for quit
+ gtk->quit_button = gtk_button_new_with_label("Quit");
+ g_signal_connect(gtk->quit_button, "clicked", G_CALLBACK(gtk->close_window), gtk);
+ gtk_grid_attach(GTK_GRID(gtk->grid), gtk->quit_button, 1, 1, 1, 1);
+
+ // set window
+ gtk_window_present(GTK_WINDOW(gtk->window));
+}
+
+GTKUI::GTKUI(int argc, char* argv[])
+{
+ this->audiodata = new AudioData;
+ app = gtk_application_new("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS);
+ g_signal_connect(app, "activate", G_CALLBACK(activate), this);
+ status = g_application_run(G_APPLICATION(app), argc, argv);
+ g_object_unref(app);
+}