From c1a8a724d73a62f6e8a0baa5e44e85e3476c0a71 Mon Sep 17 00:00:00 2001 From: fwcd Date: Thu, 29 Feb 2024 18:22:35 +0100 Subject: [PATCH] [portmidi] Add overlay with iOS patches --- overlay/ports/portmidi/ios-support.patch | 385 +++++++++++++++++++++++ overlay/ports/portmidi/portfile.cmake | 31 ++ overlay/ports/portmidi/usage | 4 + overlay/ports/portmidi/vcpkg.json | 23 ++ 4 files changed, 443 insertions(+) create mode 100644 overlay/ports/portmidi/ios-support.patch create mode 100644 overlay/ports/portmidi/portfile.cmake create mode 100644 overlay/ports/portmidi/usage create mode 100644 overlay/ports/portmidi/vcpkg.json diff --git a/overlay/ports/portmidi/ios-support.patch b/overlay/ports/portmidi/ios-support.patch new file mode 100644 index 00000000000000..22debe6d3c5ffd --- /dev/null +++ b/overlay/ports/portmidi/ios-support.patch @@ -0,0 +1,385 @@ +diff --git a/pm_mac/pmmacosxcm.c b/pm_mac/pmmacosxcm.c +index 39285ed..6d2980a 100755 +--- a/pm_mac/pmmacosxcm.c ++++ b/pm_mac/pmmacosxcm.c +@@ -75,14 +75,15 @@ + #include "pmutil.h" + #include "pminternal.h" + #include "porttime.h" ++#include "ptmacosx.h" + #include "pmmacosxcm.h" + ++#include + #include + #include + + #include + #include +-#include + #include + #include + +@@ -199,7 +200,7 @@ extern pm_fns_node pm_macosx_out_dictionary; + + typedef struct coremidi_info_struct { + int is_virtual; /* virtual device (TRUE) or actual device (FALSE)? */ +- UInt64 delta; /* difference between stream time and real time in ns */ ++ uint64_t delta; /* difference between stream time and real time in ns */ + int sysex_mode; /* middle of sending sysex */ + uint32_t sysex_word; /* accumulate data when receiving sysex */ + uint32_t sysex_byte_count; /* count how many received */ +@@ -213,10 +214,10 @@ typedef struct coremidi_info_struct { + /* allow for running status (is running status possible here? -rbd): -cpr */ + unsigned char last_command; + int32_t last_msg_length; +- UInt64 min_next_time; /* when can the next send take place? (host time) */ ++ uint64_t min_next_time; /* when can the next send take place? (host time) */ + int isIACdevice; + Float64 us_per_host_tick; /* host clock frequency, units of min_next_time */ +- UInt64 host_ticks_per_byte; /* host clock units per byte at maximum rate */ ++ uint64_t host_ticks_per_byte; /* host clock units per byte at maximum rate */ + } coremidi_info_node, *coremidi_info_type; + + /* private function declarations */ +@@ -258,10 +259,10 @@ static int midi_length(int32_t msg) + static PmTimestamp midi_synchronize(PmInternal *midi) + { + coremidi_info_type info = (coremidi_info_type) midi->api_info; +- UInt64 pm_stream_time_2 = // current time in ns +- AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); ++ uint64_t pm_stream_time_2 = // current time in ns ++ Pt_HostTimeToNanos(Pt_CurrentHostTime()); + PmTimestamp real_time; // in ms +- UInt64 pm_stream_time; // in ns ++ uint64_t pm_stream_time; // in ns + /* if latency is zero and this is an output, there is no + time reference and midi_synchronize should never be called */ + assert(midi->time_proc); +@@ -270,11 +271,10 @@ static PmTimestamp midi_synchronize(PmInternal *midi) + /* read real_time between two reads of stream time */ + pm_stream_time = pm_stream_time_2; + real_time = (*midi->time_proc)(midi->time_info); +- pm_stream_time_2 = AudioConvertHostTimeToNanos( +- AudioGetCurrentHostTime()); ++ pm_stream_time_2 = Pt_HostTimeToNanos(Pt_CurrentHostTime()); + /* repeat if more than 0.5 ms has elapsed */ + } while (pm_stream_time_2 > pm_stream_time + 500000); +- info->delta = pm_stream_time - ((UInt64) real_time * (UInt64) 1000000); ++ info->delta = pm_stream_time - ((uint64_t) real_time * (uint64_t) 1000000); + midi->sync_time = real_time; + return real_time; + } +@@ -415,20 +415,20 @@ static void read_callback(const MIDIPacketList *newPackets, PmInternal *midi) + */ + CM_DEBUG printf("read_callback packet @ %lld ns (host %lld) " + "status %x length %d\n", +- AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()), +- AudioGetCurrentHostTime(), ++ Pt_HostTimeToNanos(Pt_CurrentHostTime()), ++ Pt_CurrentHostTime(), + packet->data[0], packet->length); + for (packetIndex = 0; packetIndex < newPackets->numPackets; packetIndex++) { + /* Set the timestamp and dispatch this message */ + CM_DEBUG printf(" packet->timeStamp %lld ns %lld host\n", + packet->timeStamp, +- AudioConvertHostTimeToNanos(packet->timeStamp)); ++ Pt_HostTimeToNanos(packet->timeStamp)); + if (packet->timeStamp == 0) { + event.timestamp = now; + } else { + event.timestamp = (PmTimestamp) /* explicit conversion */ ( +- (AudioConvertHostTimeToNanos(packet->timeStamp) - info->delta) / +- (UInt64) 1000000); ++ (Pt_HostTimeToNanos(packet->timeStamp) - info->delta) / ++ (uint64_t) 1000000); + } + status = packet->data[0]; + /* process packet as sysex data if it begins with MIDI_SYSEX, or +@@ -474,8 +474,8 @@ static void virtual_read_callback(const MIDIPacketList *newPackets, + newPackets->packet[0].length == 8 && + /* CoreMIDI declares packets with 4-byte alignment, so we + * should be safe to test for 8 0xFF's as 2 32-bit values: */ +- *(SInt32 *) &newPackets->packet[0].data[0] == -1 && +- *(SInt32 *) &newPackets->packet[0].data[4] == -1) { ++ *(int32_t *) &newPackets->packet[0].data[0] == -1 && ++ *(int32_t *) &newPackets->packet[0].data[4] == -1) { + CM_DEBUG printf("got close request packet\n"); + pm_descriptors[id].pub.opened = FALSE; + return; +@@ -505,9 +505,9 @@ static coremidi_info_type create_macosxcm_info(int is_virtual, int is_input) + info->last_msg_length = 0; + info->min_next_time = 0; + info->isIACdevice = FALSE; +- info->us_per_host_tick = 1000000.0 / AudioGetHostClockFrequency(); ++ info->us_per_host_tick = Pt_MicrosPerHostTick(); + info->host_ticks_per_byte = +- (UInt64) (1000000.0 / (info->us_per_host_tick * MAX_BYTES_PER_S)); ++ (uint64_t) (1000000.0 / (info->us_per_host_tick * MAX_BYTES_PER_S)); + info->packetList = (is_input ? NULL : + (MIDIPacketList *) info->packetBuffer); + return info; +@@ -581,7 +581,7 @@ static PmError midi_in_close(PmInternal *midi) + } + } else { + /* make "close virtual port" message */ +- SInt64 close_port_bytes = 0xFFFFFFFFFFFFFFFF; ++ int64_t close_port_bytes = 0xFFFFFFFFFFFFFFFF; + /* memory requirements: packet count (4), timestamp (8), length (2), + * data (8). Total: 22, but we allocate plenty more: + */ +@@ -754,7 +754,7 @@ static PmError midi_write_flush(PmInternal *midi, PmTimestamp timestamp) + if (info->packet != NULL) { + /* out of space, send the buffer and start refilling it */ + /* update min_next_time each flush to support rate limit */ +- UInt64 host_now = AudioGetCurrentHostTime(); ++ uint64_t host_now = Pt_CurrentHostTime(); + if (host_now > info->min_next_time) + info->min_next_time = host_now; + if (info->is_virtual) { +@@ -780,8 +780,8 @@ static PmError send_packet(PmInternal *midi, Byte *message, + CM_DEBUG printf("add %d to packet %p len %d timestamp %lld @ %lld ns " + "(host %lld)\n", + message[0], info->packet, messageLength, timestamp, +- AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()), +- AudioGetCurrentHostTime()); ++ Pt_HostTimeToNanos(Pt_CurrentHostTime()), ++ Pt_CurrentHostTime()); + info->packet = MIDIPacketListAdd(info->packetList, + sizeof(info->packetBuffer), info->packet, + timestamp, messageLength, message); +@@ -842,11 +842,11 @@ static PmError midi_write_short(PmInternal *midi, PmEvent *event) + * latency is zero. Both mean no timing and send immediately. + */ + if (when == 0 || midi->latency == 0) { +- timestamp = AudioGetCurrentHostTime(); ++ timestamp = Pt_CurrentHostTime(); + } else { /* translate PortMidi time + latency to CoreMIDI time */ +- timestamp = ((UInt64) (when + midi->latency) * (UInt64) 1000000) + ++ timestamp = ((uint64_t) (when + midi->latency) * (uint64_t) 1000000) + + info->delta; +- timestamp = AudioConvertNanosToHostTime(timestamp); ++ timestamp = Pt_NanosToHostTime(timestamp); + } + + message[0] = Pm_MessageStatus(what); +@@ -876,7 +876,7 @@ static PmError midi_write_short(PmInternal *midi, PmEvent *event) + + static PmError midi_begin_sysex(PmInternal *midi, PmTimestamp when) + { +- UInt64 when_ns; ++ uint64_t when_ns; + coremidi_info_type info = (coremidi_info_type) midi->api_info; + assert(info); + info->sysex_byte_count = 0; +@@ -885,13 +885,13 @@ static PmError midi_begin_sysex(PmInternal *midi, PmTimestamp when) + if (when == 0) when = midi->now; + /* if latency == 0, midi->now is not valid. We will just set it to zero */ + if (midi->latency == 0) when = 0; +- when_ns = ((UInt64) (when + midi->latency) * (UInt64) 1000000) + ++ when_ns = ((uint64_t) (when + midi->latency) * (uint64_t) 1000000) + + info->delta; + info->sysex_timestamp = +- (MIDITimeStamp) AudioConvertNanosToHostTime(when_ns); +- UInt64 now; /* only make system time call when writing a virtual port */ ++ (MIDITimeStamp) Pt_NanosToHostTime(when_ns); ++ uint64_t now; /* only make system time call when writing a virtual port */ + if (info->is_virtual && info->sysex_timestamp < +- (now = AudioGetCurrentHostTime())) { ++ (now = Pt_CurrentHostTime())) { + info->sysex_timestamp = now; + } + +@@ -963,24 +963,23 @@ static unsigned int midi_check_host_error(PmInternal *midi) + return FALSE; + } + +- + MIDITimeStamp timestamp_pm_to_cm(PmTimestamp timestamp) + { +- UInt64 nanos; ++ uint64_t nanos; + if (timestamp <= 0) { + return (MIDITimeStamp)0; + } else { +- nanos = (UInt64)timestamp * (UInt64)1000000; +- return (MIDITimeStamp)AudioConvertNanosToHostTime(nanos); ++ nanos = (uint64_t)timestamp * (uint64_t)1000000; ++ return (MIDITimeStamp)Pt_NanosToHostTime(nanos); + } + } + + + PmTimestamp timestamp_cm_to_pm(MIDITimeStamp timestamp) + { +- UInt64 nanos; +- nanos = AudioConvertHostTimeToNanos(timestamp); +- return (PmTimestamp)(nanos / (UInt64)1000000); ++ uint64_t nanos; ++ nanos = Pt_HostTimeToNanos(timestamp); ++ return (PmTimestamp)(nanos / (uint64_t)1000000); + } + + +@@ -1094,9 +1093,9 @@ static CFStringRef ConnectedEndpointName(MIDIEndpointRef endpoint, + nConnected = CFDataGetLength(connections) / + (int32_t) sizeof(MIDIUniqueID); + if (nConnected) { +- const SInt32 *pid = (const SInt32 *)(CFDataGetBytePtr(connections)); ++ const int32_t *pid = (const int32_t *)(CFDataGetBytePtr(connections)); + for (i = 0; i < nConnected; ++i, ++pid) { +- MIDIUniqueID id = EndianS32_BtoN(*pid); ++ MIDIUniqueID id = CFSwapInt32BigToHost(*pid); + MIDIObjectRef connObject; + MIDIObjectType connObjectType; + err = MIDIObjectFindByUniqueID(id, &connObject, +diff --git a/porttime/ptmacosx.h b/porttime/ptmacosx.h +new file mode 100755 +index 0000000..4795f62 +--- /dev/null ++++ b/porttime/ptmacosx.h +@@ -0,0 +1,21 @@ ++/** @file ptmacosx.h portable timer implementation for mac os x. */ ++ ++#include // needed for uint64_t ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++uint64_t Pt_CurrentHostTime(void); ++ ++uint64_t Pt_NanosToHostTime(uint64_t nanos); ++ ++uint64_t Pt_HostTimeToNanos(uint64_t host_time); ++ ++uint64_t Pt_MicrosPerHostTick(void); ++ ++/** @} */ ++ ++#ifdef __cplusplus ++} ++#endif +diff --git a/porttime/ptmacosx_mach.c b/porttime/ptmacosx_mach.c +index 1390af8..8d74b56 100755 +--- a/porttime/ptmacosx_mach.c ++++ b/porttime/ptmacosx_mach.c +@@ -1,8 +1,8 @@ + /* ptmacosx.c -- portable timer implementation for mac os x */ + + #include ++#include + #include +-#include + + #import + #import +@@ -10,8 +10,16 @@ + #import + #include + #include ++#include ++ ++#if TARGET_OS_OSX ++#include ++#else ++#include ++#endif + + #include "porttime.h" ++#include "ptmacosx.h" + #include "sys/time.h" + #include "pthread.h" + +@@ -29,7 +37,7 @@ + #endif + + static int time_started_flag = FALSE; +-static UInt64 start_time; ++static uint64_t start_time; + static pthread_t pt_thread_pid; + + /* note that this is static data -- we only need one copy */ +@@ -115,12 +123,12 @@ static void *Pt_CallbackProc(void *p) + parameters->id); */ + while (pt_callback_proc_id == parameters->id) { + /* wait for a multiple of resolution ms */ +- UInt64 wait_time; ++ uint64_t wait_time; + int delay = mytime++ * parameters->resolution - Pt_Time(); + PtTimestamp timestamp; + if (delay < 0) delay = 0; +- wait_time = AudioConvertNanosToHostTime((UInt64)delay * NSEC_PER_MSEC); +- wait_time += AudioGetCurrentHostTime(); ++ wait_time = Pt_NanosToHostTime((uint64_t)delay * NSEC_PER_MSEC); ++ wait_time += Pt_CurrentHostTime(); + mach_wait_until(wait_time); + timestamp = Pt_Time(); + (*(parameters->callback))(timestamp, parameters->userData); +@@ -133,7 +141,7 @@ static void *Pt_CallbackProc(void *p) + PtError Pt_Start(int resolution, PtCallback *callback, void *userData) + { + if (time_started_flag) return ptAlreadyStarted; +- start_time = AudioGetCurrentHostTime(); ++ start_time = Pt_CurrentHostTime(); + + if (callback) { + int res; +@@ -191,9 +199,9 @@ int Pt_Started(void) + + PtTimestamp Pt_Time(void) + { +- UInt64 clock_time, nsec_time; +- clock_time = AudioGetCurrentHostTime() - start_time; +- nsec_time = AudioConvertHostTimeToNanos(clock_time); ++ uint64_t clock_time, nsec_time; ++ clock_time = Pt_CurrentHostTime() - start_time; ++ nsec_time = Pt_HostTimeToNanos(clock_time); + return (PtTimestamp)(nsec_time / NSEC_PER_MSEC); + } + +@@ -202,3 +210,45 @@ void Pt_Sleep(int32_t duration) + { + usleep(duration * 1000); + } ++ ++uint64_t Pt_CurrentHostTime(void) ++{ ++#if TARGET_OS_OSX ++ return AudioGetCurrentHostTime(); ++#else ++ return mach_absolute_time(); ++#endif ++} ++ ++uint64_t Pt_NanosToHostTime(uint64_t nanos) ++{ ++#if TARGET_OS_OSX ++ return AudioConvertNanosToHostTime(nanos); ++#else ++ mach_timebase_info_data_t clock_timebase; ++ mach_timebase_info(&clock_timebase); ++ return (nanos * clock_timebase.denom) / clock_timebase.numer; ++#endif ++} ++ ++uint64_t Pt_HostTimeToNanos(uint64_t host_time) ++{ ++#if TARGET_OS_OSX ++ return AudioConvertHostTimeToNanos(host_time); ++#else ++ mach_timebase_info_data_t clock_timebase; ++ mach_timebase_info(&clock_timebase); ++ return (host_time * clock_timebase.numer) / clock_timebase.denom; ++#endif ++} ++ ++uint64_t Pt_MicrosPerHostTick(void) ++{ ++#if TARGET_OS_OSX ++ return 1000000.0 / AudioGetHostClockFrequency(); ++#else ++ mach_timebase_info_data_t clock_timebase; ++ mach_timebase_info(&clock_timebase); ++ return clock_timebase.numer / (clock_timebase.denom * 1000.0); ++#endif ++} diff --git a/overlay/ports/portmidi/portfile.cmake b/overlay/ports/portmidi/portfile.cmake new file mode 100644 index 00000000000000..d6d98a28c5704d --- /dev/null +++ b/overlay/ports/portmidi/portfile.cmake @@ -0,0 +1,31 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO PortMidi/portmidi + REF "928520f7b79f371854387cb480b4e3b5bf5dac95" + SHA512 e5ba3f794d8c9b86099d7ec23eb662202a2c8a405e01e06b6dca6eda9d10c04d5ad94b6998b0ece428ed34837b72695d459dfb0a9d81ce178422398f38860933 + HEAD_REF master + PATCHES + "ios-support.patch" # Upstream PR: https://github.com/PortMidi/portmidi/pull/65 +) + +if(VCPKG_CRT_LINKAGE STREQUAL static) + set(PM_USE_STATIC_RUNTIME ON) +else() + set(PM_USE_STATIC_RUNTIME OFF) +endif() + +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}" + OPTIONS + -DPM_USE_STATIC_RUNTIME="${PM_USE_STATIC_RUNTIME}" +) + +vcpkg_cmake_install() +vcpkg_copy_pdbs() +vcpkg_fixup_pkgconfig() +vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/PortMidi) + +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") + +file(INSTALL "${CURRENT_PORT_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}") +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/license.txt") diff --git a/overlay/ports/portmidi/usage b/overlay/ports/portmidi/usage new file mode 100644 index 00000000000000..9851cb79f02a52 --- /dev/null +++ b/overlay/ports/portmidi/usage @@ -0,0 +1,4 @@ +portmidi provides CMake targets: + + find_package(PortMidi CONFIG REQUIRED) + target_link_libraries(main PRIVATE PortMidi::portmidi) diff --git a/overlay/ports/portmidi/vcpkg.json b/overlay/ports/portmidi/vcpkg.json new file mode 100644 index 00000000000000..4b57bec5173ec4 --- /dev/null +++ b/overlay/ports/portmidi/vcpkg.json @@ -0,0 +1,23 @@ +{ + "name": "portmidi", + "version": "2.0.4", + "port-version": 4, + "description": "PortMidi is a cross platform (Windows, macOS, Linux, and BSDs which support alsalib) library for interfacing with operating systems' MIDI I/O APIs.", + "homepage": "https://github.com/PortMidi/portmidi", + "license": "MIT", + "supports": "!uwp", + "dependencies": [ + { + "name": "alsa", + "platform": "linux | android | freebsd | openbsd" + }, + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ] +}