#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);
}
}