summaryrefslogtreecommitdiffstats
path: root/src/web.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/web.c')
-rw-r--r--src/web.c257
1 files changed, 257 insertions, 0 deletions
diff --git a/src/web.c b/src/web.c
new file mode 100644
index 0000000..e23d8b2
--- /dev/null
+++ b/src/web.c
@@ -0,0 +1,257 @@
+#include "web.h"
+
+#include <libwebsockets.h>
+#include <pthread.h>
+#include <microhttpd.h>
+#include <unistd.h>
+
+
+#define HTTP_PORT 9966
+#define WS_PORT 9967
+
+static struct lws *client_wsi = NULL;
+synth_t * synthx;
+struct MHD_Daemon *server;
+pthread_t server_thread;
+#define BUFFER_SIZE 1024 * 4
+char message_buffer[BUFFER_SIZE];
+
+// Function to handle slider changes
+void handle_slider_change(void *cls, int value) {
+ synth_t *synth = (synth_t*)cls;
+ printf("Slider changed: %d\n", value);
+ cc_set(&synth->cc_cutoff, value);
+}
+
+void handle_button_click(void *cls) {
+ printf("Button clicked!!!");
+ synth_t *synth = (synth_t*)cls;
+
+ int i = 5;
+ //printf("Note On : %s[%d] %fHz\n", int_to_note(i % 12), (synth->octave + (i / 12)) % 8, note);
+ synth->midi_note[i].freq = 16.35160 * pow(2, (synth->octave + i / 12.0));
+ //synth->midi_note[i].freq = notes[i % 12][(synth->octave + (i / 12)) % 8];
+ synth->midi_note[i].channel = -1;
+ synth->midi_note[i].noteOn = Pa_GetStreamTime(synth->stream);
+ synth->midi_note[i].noteOff = 0;
+ synth->midi_note[i].velocity = 1.0;
+ synth->midi_note[i].elapsed = 0;
+ synth->midi_note[i].active = 1;
+ int flag = 1;
+ for (int j = 0; j < synth->midi_active_n; j++) {
+ if (synth->midi_active[j] == &synth->midi_note[i]) {
+ flag = 0;
+ }
+ }
+ if (flag) {
+ synth->midi_active[synth->midi_active_n++] = &synth->midi_note[i];
+ }
+
+ //synth->adsr.elapsed = 0;
+ synth->active = 1;
+
+ usleep(500000);
+
+ synth->midi_note[i].noteOff = Pa_GetStreamTime(synth->stream);
+ synth->midi_note[i].noteOffSample = synth->midi_note[i].elapsed;
+
+}
+
+
+const char *html_header =
+ "HTTP/1.1 200 OK\r\n"
+ "Connection: close\r\n"
+ "Content-Length: %d\r\n"
+ "\r\n"
+ "\r\n";
+
+// HTML page with a slider
+const char *html_content =
+ "<!DOCTYPE html>\n"
+ "<html>\n"
+ "<head>\n"
+ "<title>C SYNTH WEB!</title>\n"
+ "</head>\n"
+ "<body>\n"
+ "<input id='slider' style='width: 100%; height: 200px;' type='range' min='1' max='22000' />\n"
+ "<button onclick='onButtonClick()'>Trigger</button>\n"
+ "<button id='but'>ws</button>\n"
+ "<script>\n"
+ "const ws = new WebSocket('ws://10.0.0.10:9967');\n"
+ "const slider = document.getElementById('slider');\n"
+ "const but = document.getElementById('but');\n"
+ "\n"
+ "slider.oninput = function() { ws.send(slider.value); };\n"
+ "\n"
+ "but.onclick = function() { ws.send('THIS IS A TEST DONT KILL ME'); };\n"
+ "\n"
+ "ws.onmessage = function(event) {\n"
+ " console.log('Message from server: ' + event.data);\n"
+ " slider.value = parseInt(event.data);"
+ "};\n"
+ "ws.onopen = function() {\n"
+ " console.log('Connected to WebSocket server');\n"
+ "};\n"
+ "ws.onerror = function(error) {\n"
+ " console.error('WebSocket error: ' + error);\n"
+ "};\n"
+ "</script>\n"
+ "</body>\n"
+ "</html>\n";
+
+// HTTP request handler
+enum MHD_Result handle_request(void *cls, struct MHD_Connection *connection,
+ const char *url, const char *method,
+ const char *version, const char *upload_data,
+ size_t *upload_data_size, void **con_cls) {
+ struct MHD_Response *response;
+ enum MHD_Result ret;
+
+ if (strcmp(url, "/slider") == 0 && strcmp(method, "GET") == 0) {
+ const char *value_str = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "value");
+ if (value_str) {
+ int value = atoi(value_str);
+ handle_slider_change(cls, value);
+ }
+ response = MHD_create_response_from_buffer(0, "", MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
+ MHD_destroy_response(response);
+ return ret;
+ }
+
+ if (strcmp(url, "/button") == 0 && strcmp(method, "GET") == 0) {
+ handle_button_click(cls);
+ response = MHD_create_response_from_buffer(0, "", MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
+ MHD_destroy_response(response);
+ return ret;
+ }
+
+ response = MHD_create_response_from_buffer(strlen(html_content), (void *)html_content, MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
+ MHD_destroy_response(response);
+ return ret;
+}
+
+// Callback to handle WebSocket events
+static int callback_ws(struct lws *wsi, enum lws_callback_reasons reason,
+ void *user, void *in, size_t len) {
+ char buf[10000] = "";
+ char tmp[10000] = "";
+ switch (reason) {
+ case LWS_CALLBACK_ESTABLISHED: { // When a connection is established
+ client_wsi = wsi; // Store the WebSocket connection for later use
+ printf("WebSocket connection established with client: %p\n", wsi);
+ /* const char *msg = "Hello, Client!"; */
+ /* printf("Sending message: %s\n", msg); */
+ /* int n = lws_write(wsi, (unsigned char *)msg, strlen(msg), LWS_WRITE_TEXT); */
+ /* if (n < 0) { */
+ /* printf("Error sending message, error code: %d\n", n); */
+ /* } */
+ break;
+ }
+ case LWS_CALLBACK_RECEIVE: { // When a message is received
+ char buffer[128];
+ snprintf(buffer, sizeof(buffer), "%.*s", (int)len, (char *)in);
+ printf("Received slider value: %s\n", buffer);
+ //lws_write(wsi, (unsigned char *)in, len, LWS_WRITE_TEXT);
+ int value = atoi(buffer);
+ handle_slider_change(synthx, value);
+ break;
+ }
+ case LWS_CALLBACK_SERVER_WRITEABLE: {
+ printf("\nLWS_CALLBACK_SERVER_WRITEABLE\n\n");
+ /* size_t msg_len = strlen(message_buffer); */
+ /* unsigned char buffer[LWS_PRE + BUFFER_SIZE]; */
+ /* memcpy(&buffer[LWS_PRE], message_buffer, msg_len); */
+ /* lws_write(wsi, (unsigned char *)buffer, strlen(buffer), LWS_WRITE_TEXT); */
+ break;
+ }
+ case LWS_CALLBACK_HTTP: {
+ snprintf(tmp, sizeof(tmp), html_header, strlen(html_content));
+ strcpy(buf, tmp);
+ printf("\nHTTP?!\n\n%s\n", tmp);
+ strcat(buf, html_content);
+ lws_write(wsi, (unsigned char *)buf, strlen(buf), LWS_WRITE_HTTP);
+ return -1;
+ break;
+ }
+ case LWS_CALLBACK_CLOSED: {
+ printf("WebSocket connection closed with client: %p\n", wsi);
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+// Thread function to run the WebSocket server
+void *websocket_server_thread(void *arg) {
+ struct lws_context_creation_info info;
+ struct lws_context *context;
+ struct lws_protocols protocols[] = {
+ //{ "http-only", callback_http, 0, 0 },
+ { "ws", callback_ws, 0, 128 },
+ { NULL, NULL, 0, 0 } // Terminator
+ };
+
+ memset(&info, 0, sizeof(info));
+ info.port = WS_PORT;
+ //info.user = arg;
+ info.protocols = protocols;
+ info.pt_serv_buf_size = 32 * 1024;
+ info.options = LWS_SERVER_OPTION_VALIDATE_UTF8;
+
+ context = lws_create_context(&info);
+ if (!context) {
+ fprintf(stderr, "lws_create_context failed\n");
+ return NULL;
+ }
+
+ printf("WebSocket server running on ws://localhost:%d\n", WS_PORT);
+
+ while (1) {
+ lws_service(context, 1000); // Service WebSocket events
+ }
+
+ lws_context_destroy(context);
+ return NULL;
+}
+
+void
+init_web(synth_t * synth)
+{
+ synthx = synth;
+ // Start the HTTP server
+ server = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION, HTTP_PORT, NULL, NULL, &handle_request, (void *)synth, MHD_OPTION_END);
+ if (server == NULL) {
+ fprintf(stderr, "Failed to start server\n");
+ return;
+ }
+
+ // Create a new thread for the WebSocket server
+ if (pthread_create(&server_thread, NULL, websocket_server_thread, NULL) != 0) {
+ fprintf(stderr, "Failed to create server thread\n");
+ return;
+ }
+}
+
+void
+free_web()
+{
+ MHD_stop_daemon(server);
+}
+
+void ws_send_message(const char *message) {
+ if (client_wsi != NULL) {
+ /* strcpy(message_buffer, message); */
+ /* lws_callback_on_writable(client_wsi); */
+ size_t msg_len = strlen(message);
+ unsigned char buffer[LWS_PRE + BUFFER_SIZE];
+ memcpy(&buffer[LWS_PRE], message, msg_len);
+ lws_write(client_wsi, &buffer[LWS_PRE], msg_len, LWS_WRITE_TEXT);
+ printf("[WS]: Sent <<%s>>\n", message);
+
+ //lws_write(client_wsi, (unsigned char *)message, strlen(message), LWS_WRITE_TEXT);
+ }
+}