#include "web.h"
#define _GNU_SOURCE
#include <libwebsockets.h>
#include <pthread.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];
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 [http://localhost:%d]\n", WS_PORT, 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;
lws_set_log_level(LLL_WARN, NULL);
// 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);
}
}