aboutsummaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c153
1 files changed, 153 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..64bceaa
--- /dev/null
+++ b/main.c
@@ -0,0 +1,153 @@
+#include <gtk/gtk.h>
+#include <cairo/cairo.h>
+#include <portaudio.h>
+
+int device = -1;
+
+typedef struct {
+ float left;
+ float right;
+} AudioData;
+
+AudioData audiodata;
+
+struct data {
+ int device_num;
+};
+
+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;
+
+ if (data->left > 0) {
+ data->left -= 0.005;
+ }
+
+ if (data->right > 0) {
+ data->right -= 0.005;
+ }
+
+ for (unsigned long i = 0; i < framesPerBuffer * 2; i += 2) {
+ data->left = MAX(data->left, fabs(in[i]));
+ data->right = MAX(data->right, fabs(in[i + 1]));
+ }
+
+ if (drawing_area) {
+ gtk_widget_queue_draw(GTK_WIDGET(drawing_area));
+ }
+
+ return 0;
+}
+
+static void select_device(GtkWidget *widget, gpointer data)
+{
+ struct data *d = (struct data *)data;
+ device = d->device_num;
+ printf("Device %d selected\n", d->device_num);
+
+ PaStreamParameters inputParameters;
+ memset(&inputParameters, 0, sizeof(inputParameters));
+ inputParameters.channelCount = 2;
+ inputParameters.device = device;
+ inputParameters.hostApiSpecificStreamInfo = NULL;
+ inputParameters.sampleFormat = paFloat32;
+ inputParameters.suggestedLatency = Pa_GetDeviceInfo(device)->defaultLowInputLatency;
+
+ Pa_OpenStream(&stream, &inputParameters, NULL, Pa_GetDeviceInfo(device)->defaultSampleRate, FRAMES_PER_BUFFER, paNoFlag, patestCallback, &audiodata);
+ Pa_StartStream(stream);
+}
+
+static void draw(cairo_t *cr, GtkWidget *area)
+{
+ cairo_set_source_rgba(cr, 1, 0, 0, 1);
+ cairo_arc(cr, 250, 250, audiodata.left * 250, 0, 2 * M_PI);
+ cairo_arc(cr, 800, 250, audiodata.right * 250, 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, data);
+}
+
+static void refresh()
+{
+}
+
+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, 1050, 500);
+ 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();
+ 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);
+ }
+
+ // init button for every audio device
+ for (int i = 0; i < numDevices; i++) {
+ const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(i);
+ struct data *d = malloc(sizeof(struct data));
+ d->device_num = i;
+ button = gtk_button_new_with_label(deviceInfo->name);
+ g_signal_connect(button, "clicked", G_CALLBACK(select_device), d);
+ gtk_grid_attach(GTK_GRID(grid), button, 0, numDevices - i - 1, 1, 1);
+ }
+
+ // init button for refresh
+ button = gtk_button_new_with_label("Refresh");
+ g_signal_connect_swapped(button, "clicked", G_CALLBACK(refresh), window);
+ 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(gtk_window_destroy), 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;
+}