shithub: m8c

Download patch

ref: dc9503f082e21098218c2657a3a15c32c2d39b76
parent: a701f7c3847a0226d30623a5c54033f58715bae1
author: Jonne Kokkonen <jonne.kokkonen@gmail.com>
date: Sun Mar 23 12:33:35 EDT 2025

Refactor MIDI initialization and add queue size handling.

Extract MIDI device detection to a dedicated function, improve device disconnection handling, and centralize MIDI port cleanup logic. Extend the queue API with a function to retrieve its size and document all queue functions.

--- a/src/backends/m8_rtmidi.c
+++ b/src/backends/m8_rtmidi.c
@@ -127,15 +127,8 @@
   return 1;
 }
 
-int m8_initialize(const int verbose, const char *preferred_device) {
-
-  int midi_in_initialized = 0;
-  int midi_out_initialized = 0;
-
-  SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "init_serial called");
-  if (midi_in == NULL || midi_out == NULL) {
-    initialize_rtmidi();
-  };
+int detect_m8_midi_device(const int verbose, const char *preferred_device) {
+  int m8_midi_port_number = -1;
   const unsigned int ports_total_in = rtmidi_get_port_count(midi_in);
   if (verbose)
     SDL_Log("Number of MIDI in ports: %d", ports_total_in);
@@ -146,16 +139,10 @@
     rtmidi_get_port_name(midi_in, port_number, &port_name[0], &port_name_length_in);
     if (verbose)
       SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "MIDI IN port %d, name: %s", port_number, port_name);
-
     if (SDL_strncmp("M8", port_name, 2) == 0) {
+      m8_midi_port_number = port_number;
       if (verbose)
         SDL_Log("Found M8 Input in MIDI port %d", port_number);
-      rtmidi_in_ignore_types(midi_in, false, true, true);
-      rtmidi_open_port(midi_in, port_number, "M8");
-      midi_in_initialized = 1;
-      rtmidi_open_port(midi_out, port_number, "M8");
-      midi_out_initialized = 1;
-      init_queue(&queue);
       if (preferred_device != NULL && SDL_strcmp(preferred_device, port_name) == 0) {
         SDL_Log("Found preferred device, breaking");
         break;
@@ -162,11 +149,25 @@
       }
     }
   }
-  return midi_in_initialized && midi_out_initialized;
+  return m8_midi_port_number;
 }
 
-int check_serial_port(void) {
-  SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "check_serial_port called");
+int m8_initialize(const int verbose, const char *preferred_device) {
+
+  int m8_midi_port_number = 0;
+
+  SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Initialize M8 via RTMIDI called");
+  if (midi_in == NULL || midi_out == NULL) {
+    initialize_rtmidi();
+  };
+  m8_midi_port_number = detect_m8_midi_device(verbose, preferred_device);
+  if (m8_midi_port_number >= 0) {
+    rtmidi_in_ignore_types(midi_in, false, true, true); // Allow sysex
+    rtmidi_open_port(midi_in, m8_midi_port_number, "M8");
+    rtmidi_open_port(midi_out, m8_midi_port_number, "M8");
+    init_queue(&queue);
+    return 1;
+  }
   return 0;
 }
 
@@ -175,7 +176,7 @@
   const unsigned char reset_sysex[8] = {0xF0, 0x00, 0x02, 0x61, 0x00, 0x00, 'R', 0xF7};
   const int result = rtmidi_out_send_message(midi_out, &reset_sysex[0], sizeof(reset_sysex));
   if (result != 0) {
-    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error resetting M8 display, code %d", result);
+    SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Error resetting M8 display, error %s", midi_out->msg);
     return 0;
   }
   return 1;
@@ -193,6 +194,16 @@
   return result;
 }
 
+void close_and_free_midi_ports(void) {
+  SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Freeing MIDI ports");
+  rtmidi_close_port(midi_in);
+  rtmidi_close_port(midi_out);
+  rtmidi_in_free(midi_in);
+  rtmidi_out_free(midi_out);
+  midi_in = NULL;
+  midi_out = NULL;
+}
+
 int disconnect(void) {
   const unsigned char disconnect_sysex[8] = {0xF0, 0x00, 0x02, 0x61, 0x00, 0x00, 'D', 0xF7};
   const int result =
@@ -200,9 +211,7 @@
   if (result != 0) {
     SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, "Failed to send disconnect");
   }
-  SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Freeing MIDI ports");
-  rtmidi_in_free(midi_in);
-  rtmidi_out_free(midi_out);
+  close_and_free_midi_ports();
   return !result;
 }
 
@@ -231,12 +240,26 @@
 }
 
 int m8_process_data(config_params_s conf) {
+
   (void)conf; // unused parameter
 
-  unsigned char *command;
-  size_t length = 0;
-  while ((command = pop_message(&queue, &length)) != NULL) {
-    process_command(command, length);
+  static unsigned int empty_cycles = 0;
+
+  if (queue_size(&queue) > 0) {
+    unsigned char *command;
+    empty_cycles = 0;
+    size_t length = 0;
+    while ((command = pop_message(&queue, &length)) != NULL) {
+      process_command(command, length);
+      SDL_free(command);
+    }
+  } else {
+    empty_cycles++;
+    if (empty_cycles >= conf.wait_packets) {
+      SDL_Log("No messages received for %d cycles, assuming device disconnected", empty_cycles);
+      close_and_free_midi_ports();
+      return 0;
+    }
   }
   return 1;
 }
@@ -263,8 +286,7 @@
     rtmidi_get_port_name(midi_in, port_number, &port_name[0], &port_name_length_in);
     SDL_Log("MIDI IN port %d, name: %s", port_number, port_name);
   }
-  rtmidi_in_free(midi_in);
-  rtmidi_out_free(midi_out);
+  close_and_free_midi_ports();
   return 1;
 }
 
--- a/src/backends/queue.c
+++ b/src/backends/queue.c
@@ -12,7 +12,16 @@
     queue->cond = SDL_CreateCondition();
 }
 
+// Free allocated memory and destroy mutex
 void destroy_queue(message_queue_s *queue) {
+  SDL_LockMutex(queue->mutex);
+
+  while (queue->front != queue->rear) {
+    SDL_free(queue->messages[queue->front]);
+    queue->front = (queue->front + 1) % MAX_QUEUE_SIZE;
+  }
+
+  SDL_UnlockMutex(queue->mutex);
   SDL_DestroyMutex(queue->mutex);
   SDL_DestroyCondition(queue->cond);
 }
@@ -52,4 +61,11 @@
 
   SDL_UnlockMutex(queue->mutex);
   return message;
+}
+
+unsigned int queue_size(const message_queue_s *queue) {
+  SDL_LockMutex(queue->mutex);
+  const unsigned int size = (queue->rear - queue->front + MAX_QUEUE_SIZE) % MAX_QUEUE_SIZE;
+  SDL_UnlockMutex(queue->mutex);
+  return size;
 }
\ No newline at end of file
--- a/src/backends/queue.h
+++ b/src/backends/queue.h
@@ -18,9 +18,39 @@
   SDL_Condition *cond;
 } message_queue_s;
 
-// Initialize the message queue
+/**
+ * Initializes the message queue structure.
+ *
+ * @param queue A pointer to the message queue structure to be initialized.
+ */
 void init_queue(message_queue_s *queue);
+
+/**
+ * Retrieves and removes a message from the front of the message queue.
+ * If the queue is empty, the function returns NULL.
+ *
+ * @param queue A pointer to the message queue structure from which the message is to be retrieved.
+ * @param length A pointer to a variable where the length of the retrieved message will be stored.
+ * @return A pointer to the retrieved message, or NULL if the queue is empty.
+ */
 unsigned char *pop_message(message_queue_s *queue, size_t *length);
+
+/**
+ * Adds a new message to the message queue.
+ * If the queue is full, the message will not be added.
+ *
+ * @param queue A pointer to the message queue structure where the message is to be stored.
+ * @param message A pointer to the message data to be added to the queue.
+ * @param length The length of the message in bytes.
+ */
 void push_message(message_queue_s *queue, const unsigned char *message, size_t length);
+
+/**
+ * Calculates the current size of the message queue.
+ *
+ * @param queue A pointer to the message queue structure whose size is to be determined.
+ * @return The number of messages currently in the queue.
+ */
+unsigned int queue_size(const message_queue_s *queue);
 
 #endif // QUEUE_H
--- a/src/main.c
+++ b/src/main.c
@@ -165,7 +165,7 @@
         renderer_close();
         inline_font_close();
         SDL_Quit();
-        return -1;
+        return 1;
       }
     }
 
--