ref: 230b71073d7fe3fee4e01f2013db91f37bfe5f3d
parent: 9c06c3f1031aef6c4d256c52bb3d283aaeb3d19e
author: Jonne Kokkonen <jonne.kokkonen@gmail.com>
date: Fri Mar 28 11:50:44 EDT 2025
Add pause/resume processing for app suspension handling Implemented m8_pause_processing and m8_resume_processing functions across backends to handle processing during app suspension. This ensures proper behavior on iOS, by pausing MIDI and other processing when the app is backgrounded and resuming it when the app returns to the foreground. Adjusted related code to integrate these changes seamlessly.
--- a/src/backends/m8.h
+++ b/src/backends/m8.h
@@ -18,6 +18,8 @@
int m8_send_msg_controller(unsigned char input);
int m8_send_msg_keyjazz(unsigned char note, unsigned char velocity);
int m8_process_data(const config_params_s *conf);
+int m8_pause_processing(void);
+int m8_resume_processing(void);
int m8_close(void);
#endif
\ No newline at end of file
--- a/src/backends/m8_libserialport.c
+++ b/src/backends/m8_libserialport.c
@@ -362,4 +362,8 @@
}
int m8_close() { return disconnect(); }+
+// These shouldn't be needed with serial
+int m8_pause_processing(void) { return 1; }+int m8_resume_processing(void) { return 1; }#endif
--- a/src/backends/m8_libusb.c
+++ b/src/backends/m8_libusb.c
@@ -364,4 +364,8 @@
return 1;
}
+// These shouldn't be needed with serial
+int m8_pause_processing(void) { return 1; }+int m8_resume_processing(void) { return 1; }+
#endif
--- a/src/backends/m8_rtmidi.c
+++ b/src/backends/m8_rtmidi.c
@@ -23,6 +23,8 @@
const unsigned int m8_sysex_header_size = sizeof(m8_sysex_header);
const unsigned char sysex_message_end = 0xF7;
+bool midi_processing_suspended = false;
+
bool message_is_m8_sysex(const unsigned char *message) { if (memcmp(m8_sysex_header, message, m8_sysex_header_size) == 0) {return true;
@@ -90,7 +92,7 @@
(void)delta_time;
(void)user_data;
- if (message_size < 5 || !message_is_m8_sysex(message))
+ if (midi_processing_suspended || message_size < 5 || !message_is_m8_sysex(message))
return;
unsigned char *decoded_data;
@@ -205,6 +207,7 @@
}
int disconnect(void) {+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Sending disconnect message to M8");
const unsigned char disconnect_sysex[8] = {0xF0, 0x00, 0x02, 0x61, 0x00, 0x00, 'D', 0xF7};const int result =
rtmidi_out_send_message(midi_out, &disconnect_sysex[0], sizeof(disconnect_sysex));
@@ -287,12 +290,9 @@
}
int m8_close() {- if (queue.mutex != NULL) {- SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Destroying command queue");
- SDL_DestroyMutex(queue.mutex);
- SDL_DestroyCondition(queue.cond);
- }
- return disconnect();
+ const int result = disconnect();
+ destroy_queue(&queue);
+ return result;
}
int m8_list_devices() {@@ -309,6 +309,18 @@
SDL_Log("MIDI IN port %d, name: %s", port_number, port_name);}
close_and_free_midi_ports();
+ return 1;
+}
+
+int m8_pause_processing(void) {+ midi_processing_suspended = true;
+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Pausing MIDI processing");
+ return 1;
+}
+int m8_resume_processing(void) {+ midi_processing_suspended = false;
+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Resuming MIDI processing");
+ m8_reset_display();
return 1;
}
--- a/src/main.c
+++ b/src/main.c
@@ -7,6 +7,7 @@
#include <SDL3/SDL.h>
#include <signal.h>
+#include <stdlib.h>
#include "SDL2_inprint.h"
#include "backends/audio.h"
@@ -17,7 +18,10 @@
#include "input.h"
#include "render.h"
-#include <stdlib.h>
+#if TARGET_OS_IOS
+#include <SDL3/SDL_main.h>
+unsigned char app_suspended = 0;
+#endif // TARGET_OS_IOS
enum app_state app_state = WAIT_FOR_DEVICE;
unsigned char device_connected = 0;
@@ -28,10 +32,10 @@
app_state = QUIT;
}
-static void initialize_signals() {+static void initialize_signals(void) {signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
-#ifdef SIGQUIT
+#ifdef SIGQUIT // Not available on Windows.
signal(SIGQUIT, signal_handler);
#endif
}
@@ -46,6 +50,7 @@
}
while (app_state == WAIT_FOR_DEVICE) {+
// get current input
const input_msg_s input = input_get_msg(&*conf);
if (input.type == special && input.value == msg_quit) {@@ -53,6 +58,14 @@
app_state = QUIT;
}
+#if TARGET_OS_IOS
+ // Handle app suspension
+ if (app_suspended) {+ SDL_Delay(conf->idle_ms);
+ continue;
+ }
+#endif // TARGET_OS_IOS
+
if (SDL_GetTicks() - ticks_update_screen > 16) {ticks_update_screen = SDL_GetTicks();
screensaver_draw();
@@ -136,7 +149,7 @@
#if TARGET_OS_IOS
// IOS events handler
-unsigned char handle_app_events(void *userdata, SDL_Event *event) {+static bool SDLCALL handle_app_events(void *userdata, SDL_Event *event) {const config_params_s *conf = (config_params_s *)userdata;
switch (event->type) {case SDL_EVENT_TERMINATING:
@@ -152,9 +165,10 @@
seconds to save all your state or the app will be terminated. Your app is NOT active at this
point.
*/
- m8_close(); // Disconnect so that buffers and queues don't fill up
- device_connected = 0;
- app_state = WAIT_FOR_DEVICE;
+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Received SDL_EVENT_DID_ENTER_BACKGROUND");
+ app_suspended = 1;
+ if (device_connected)
+ m8_pause_processing();
return 0;
case SDL_EVENT_LOW_MEMORY:
/* You will get this when your app is paused and iOS wants more memory.
@@ -170,10 +184,16 @@
/* This call happens when your app is coming back to the foreground.
Restore all your state here.
*/
+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Received SDL_EVENT_WILL_ENTER_FOREGROUND");
+ app_suspended = 0;
+ if (device_connected)
+ m8_resume_processing();
+ return 0;
case SDL_EVENT_DID_ENTER_FOREGROUND:
/* Restart your loops here.
Your app is interactive and getting CPU again.
*/
+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Received SDL_EVENT_DID_ENTER_FOREGROUND");
return 0;
default:
/* No special processing, add it to the event queue */
--
⑨