gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

pminternal.h (8301B)


      1 /* pminternal.h -- header for interface implementations */
      2 
      3 /* this file is included by files that implement library internals */
      4 /* Here is a guide to implementers:
      5      provide an initialization function similar to pm_winmm_init()
      6      add your initialization function to pm_init()
      7      Note that your init function should never require not-standard
      8          libraries or fail in any way. If the interface is not available,
      9          simply do not call pm_add_device. This means that non-standard
     10          libraries should try to do dynamic linking at runtime using a DLL
     11          and return without error if the DLL cannot be found or if there
     12          is any other failure.
     13      implement functions as indicated in pm_fns_type to open, read, write,
     14          close, etc.
     15      call pm_add_device() for each input and output device, passing it a
     16          pm_fns_type structure.
     17      assumptions about pm_fns_type functions are given below.
     18  */
     19 
     20 #ifdef __cplusplus
     21 extern "C" {
     22 #endif
     23 
     24 extern int pm_initialized; /* see note in portmidi.c */
     25 
     26 /* these are defined in system-specific file */
     27 void *pm_alloc(size_t s);
     28 void pm_free(void *ptr);
     29 
     30 /* if an error occurs while opening or closing a midi stream, set these: */
     31 extern int pm_hosterror;
     32 extern char pm_hosterror_text[PM_HOST_ERROR_MSG_LEN];
     33  
     34 struct pm_internal_struct;
     35 
     36 /* these do not use PmInternal because it is not defined yet... */
     37 typedef PmError (*pm_write_short_fn)(struct pm_internal_struct *midi, 
     38                                      PmEvent *buffer);
     39 typedef PmError (*pm_begin_sysex_fn)(struct pm_internal_struct *midi,
     40                                      PmTimestamp timestamp);
     41 typedef PmError (*pm_end_sysex_fn)(struct pm_internal_struct *midi,
     42                                    PmTimestamp timestamp);
     43 typedef PmError (*pm_write_byte_fn)(struct pm_internal_struct *midi,
     44                                     unsigned char byte, PmTimestamp timestamp);
     45 typedef PmError (*pm_write_realtime_fn)(struct pm_internal_struct *midi,
     46                                         PmEvent *buffer);
     47 typedef PmError (*pm_write_flush_fn)(struct pm_internal_struct *midi,
     48                                      PmTimestamp timestamp);
     49 typedef PmTimestamp (*pm_synchronize_fn)(struct pm_internal_struct *midi);
     50 /* pm_open_fn should clean up all memory and close the device if any part
     51    of the open fails */
     52 typedef PmError (*pm_open_fn)(struct pm_internal_struct *midi,
     53                               void *driverInfo);
     54 typedef PmError (*pm_abort_fn)(struct pm_internal_struct *midi);
     55 /* pm_close_fn should clean up all memory and close the device if any
     56    part of the close fails. */
     57 typedef PmError (*pm_close_fn)(struct pm_internal_struct *midi);
     58 typedef PmError (*pm_poll_fn)(struct pm_internal_struct *midi);
     59 typedef void (*pm_host_error_fn)(struct pm_internal_struct *midi, char * msg,
     60                                  unsigned int len);
     61 typedef unsigned int (*pm_has_host_error_fn)(struct pm_internal_struct *midi);
     62 
     63 typedef struct {
     64     pm_write_short_fn write_short; /* output short MIDI msg */
     65     pm_begin_sysex_fn begin_sysex; /* prepare to send a sysex message */
     66     pm_end_sysex_fn end_sysex; /* marks end of sysex message */
     67     pm_write_byte_fn write_byte; /* accumulate one more sysex byte */
     68     pm_write_realtime_fn write_realtime; /* send real-time message within sysex */
     69     pm_write_flush_fn write_flush; /* send any accumulated but unsent data */
     70     pm_synchronize_fn synchronize; /* synchronize portmidi time to stream time */
     71     pm_open_fn open;   /* open MIDI device */
     72     pm_abort_fn abort; /* abort */
     73     pm_close_fn close; /* close device */
     74     pm_poll_fn poll;   /* read pending midi events into portmidi buffer */
     75     pm_has_host_error_fn has_host_error; /* true when device has had host 
     76                                             error message */
     77     pm_host_error_fn host_error; /* provide text readable host error message
     78                                     for device (clears and resets) */
     79 } pm_fns_node, *pm_fns_type;
     80 
     81 
     82 /* when open fails, the dictionary gets this set of functions: */
     83 extern pm_fns_node pm_none_dictionary;
     84 
     85 typedef struct {
     86     PmDeviceInfo pub; /* some portmidi state also saved in here (for autmatic
     87                          device closing (see PmDeviceInfo struct) */
     88     void *descriptor; /* ID number passed to win32 multimedia API open */
     89     void *internalDescriptor; /* points to PmInternal device, allows automatic 
     90                                  device closing */
     91     pm_fns_type dictionary;
     92 } descriptor_node, *descriptor_type;
     93 
     94 extern int pm_descriptor_max;
     95 extern descriptor_type descriptors;
     96 extern int pm_descriptor_index;
     97 
     98 typedef uint32_t (*time_get_proc_type)(void *time_info);
     99 
    100 typedef struct pm_internal_struct {
    101     int device_id; /* which device is open (index to descriptors) */
    102     short write_flag; /* MIDI_IN, or MIDI_OUT */
    103     
    104     PmTimeProcPtr time_proc; /* where to get the time */
    105     void *time_info; /* pass this to get_time() */
    106     int32_t buffer_len; /* how big is the buffer or queue? */
    107     PmQueue *queue;
    108 
    109     int32_t latency; /* time delay in ms between timestamps and actual output */
    110                   /* set to zero to get immediate, simple blocking output */
    111                   /* if latency is zero, timestamps will be ignored; */
    112                   /* if midi input device, this field ignored */
    113     
    114     int sysex_in_progress; /* when sysex status is seen, this flag becomes
    115         * true until EOX is seen. When true, new data is appended to the
    116         * stream of outgoing bytes. When overflow occurs, sysex data is 
    117         * dropped (until an EOX or non-real-timei status byte is seen) so
    118         * that, if the overflow condition is cleared, we don't start 
    119         * sending data from the middle of a sysex message. If a sysex
    120         * message is filtered, sysex_in_progress is false, causing the
    121         * message to be dropped. */
    122     PmMessage sysex_message; /* buffer for 4 bytes of sysex data */
    123     int sysex_message_count; /* how many bytes in sysex_message so far */
    124 
    125     int32_t filters; /* flags that filter incoming message classes */
    126     int32_t channel_mask; /* filter incoming messages based on channel */
    127     PmTimestamp last_msg_time; /* timestamp of last message */
    128     PmTimestamp sync_time; /* time of last synchronization */
    129     PmTimestamp now; /* set by PmWrite to current time */
    130     int first_message; /* initially true, used to run first synchronization */
    131     pm_fns_type dictionary; /* implementation functions */
    132     void *descriptor; /* system-dependent state */
    133     /* the following are used to expedite sysex data */
    134     /* on windows, in debug mode, based on some profiling, these optimizations
    135      * cut the time to process sysex bytes from about 7.5 to 0.26 usec/byte,
    136      * but this does not count time in the driver, so I don't know if it is
    137      * important
    138      */
    139     unsigned char *fill_base; /* addr of ptr to sysex data */
    140     uint32_t *fill_offset_ptr; /* offset of next sysex byte */
    141     int32_t fill_length; /* how many sysex bytes to write */
    142 } PmInternal;
    143 
    144 
    145 /* defined by system specific implementation, e.g. pmwinmm, used by PortMidi */
    146 void pm_init(void); 
    147 void pm_term(void); 
    148 
    149 /* defined by portMidi, used by pmwinmm */
    150 PmError none_write_short(PmInternal *midi, PmEvent *buffer);
    151 PmError none_write_byte(PmInternal *midi, unsigned char byte, 
    152                         PmTimestamp timestamp);
    153 PmTimestamp none_synchronize(PmInternal *midi);
    154 
    155 PmError pm_fail_fn(PmInternal *midi);
    156 PmError pm_fail_timestamp_fn(PmInternal *midi, PmTimestamp timestamp);
    157 PmError pm_success_fn(PmInternal *midi);
    158 PmError pm_add_device(char *interf, char *name, int input, void *descriptor,
    159                       pm_fns_type dictionary);
    160 uint32_t pm_read_bytes(PmInternal *midi, const unsigned char *data, int len,
    161                            PmTimestamp timestamp);
    162 void pm_read_short(PmInternal *midi, PmEvent *event);
    163 
    164 #define none_write_flush pm_fail_timestamp_fn
    165 #define none_sysex pm_fail_timestamp_fn
    166 #define none_poll pm_fail_fn
    167 #define success_poll pm_success_fn
    168 
    169 #define MIDI_REALTIME_MASK 0xf8
    170 #define is_real_time(msg) \
    171     ((Pm_MessageStatus(msg) & MIDI_REALTIME_MASK) == MIDI_REALTIME_MASK)
    172 
    173 int pm_find_default_device(char *pattern, int is_input);
    174 
    175 #ifdef __cplusplus
    176 }
    177 #endif
    178