diff options
Diffstat (limited to 'src/web.c')
-rw-r--r-- | src/web.c | 257 |
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); + } +} |