#include "web.h" #define _GNU_SOURCE #include #include #include #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]; static char *html_content; // 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); } const char *html_header = "HTTP/1.1 200 OK\r\n" "Connection: close\r\n" "Content-Length: %d\r\n" "\r\n" "\r\n"; char *read_file_to_string(const char *filename) { FILE *file = fopen(filename, "rb"); // Open file in binary mode if (!file) { perror("Error opening file"); return NULL; } // Seek to the end to determine file size fseek(file, 0, SEEK_END); long file_size = ftell(file); rewind(file); // Go back to the beginning // Allocate memory for the file content (+1 for null terminator) char *buffer = (char *)malloc(file_size + 1); if (!buffer) { perror("Memory allocation failed"); fclose(file); return NULL; } // Read file into buffer fread(buffer, 1, file_size, file); buffer[file_size] = '\0'; // Null-terminate the string fclose(file); return buffer; } int key_to_number(char key) { switch (key) { case 'q': return 0; case '2': return 1; case 'w': return 2; case '3': return 3; case 'e': return 4; case 'r': return 5; case '5': return 6; case 't': return 7; case '6': return 8; case 'y': return 9; case '7': return 10; case 'u': return 11; case 'i': return 12; case '9': return 13; case 'o': return 14; case '0': return 15; case 'p': return 16; } return 0; } // Callback to handle WebSocket events static int callback_ws(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { (void)user; 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("Got ws message: [%s]\n", buffer); if (!strcmp("note_on", buffer)) { break; } if (!strcmp("note_off", buffer)) { break; } if (buffer[0] == '+') { char key = buffer[1]; int i = key_to_number(key); synthx->midi_note[i].freq = 16.35160 * pow(2, (synthx->octave + i / 12.0)); synthx->midi_note[i].channel = -1; synthx->midi_note[i].noteOn = Pa_GetStreamTime(synthx->stream); synthx->midi_note[i].noteOff = 0; synthx->midi_note[i].velocity = 1.0; synthx->midi_note[i].elapsed = 0; synthx->midi_note[i].active = 1; int flag = 1; for (int j = 0; j < synthx->midi_active_n; j++) { if (synthx->midi_active[j] == &synthx->midi_note[i]) { flag = 0; } } if (flag) { synthx->midi_active[synthx->midi_active_n++] = &synthx->midi_note[i]; } //synth->adsr.elapsed = 0; synthx->active = 1; break; } if (buffer[0] == '-') { char key = buffer[1]; int i = key_to_number(key); synthx->midi_note[i].noteOff = Pa_GetStreamTime(synthx->stream); synthx->midi_note[i].noteOffSample = synthx->midi_note[i].elapsed; break; } //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); strcat(buf, html_content); lws_write(wsi, (unsigned char *)buf, strlen(buf), LWS_WRITE_HTTP); 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) { (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, 0, 0, 0 }, { NULL, NULL, 0, 0, 0, 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; } char *get_from_template() { int size = 1024^3 * 1000; char * ret = (char *)malloc(sizeof(char) * size); int pipefd[2]; if (pipe(pipefd) == -1) { perror("pipe"); return NULL; } #define OUT pipefd[1] #define INT(x) dprintf(OUT, "%d", x); #define PERCENT dprintf(OUT, "%s", "%"); #include "index.html.h" close(pipefd[1]); // Read from the pipe into a buffer ssize_t bytes_read = read(pipefd[0], ret, size - 1); if (bytes_read == -1) { perror("read"); return NULL; } // Null-terminate the ret ret[bytes_read] = '\0'; close(pipefd[0]); return ret; } void init_web(synth_t * synth) { //html_content = read_file_to_string("src/index.html"); html_content = get_from_template(); synthx = synth; // 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() { free(html_content); } 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); } }