summaryrefslogblamecommitdiffstats
path: root/src/web.c
blob: e23d8b2b1c6c154a6ca96be4495f91efab4ef89c (plain) (tree)
































































































































































































































































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