|  | /*
 * Carla Native Plugin API (JACK Compatibility header)
 * Copyright (C) 2015 Filipe Coelho <falktx@falktx.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * For a full copy of the GNU General Public License see the doc/GPL.txt file.
 */
#ifndef CARLA_NATIVE_JACK_H_INCLUDED
#define CARLA_NATIVE_JACK_H_INCLUDED
#include "CarlaNative.h"
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ------------------------------------------------------------------------------------------------------------
 * Macros */
#define JACK_DEFAULT_AUDIO_TYPE "32 bit float mono audio"
#define JACK_DEFAULT_MIDI_TYPE  "8 bit raw midi"
/* ------------------------------------------------------------------------------------------------------------
 * Basic types */
typedef float    jack_default_audio_sample_t;
typedef uint8_t  jack_midi_data_t;
typedef uint32_t jack_nframes_t;
typedef void (*jack_shutdown_callback)(void* ptr);
typedef int  (*jack_process_callback)(jack_nframes_t nframes, void* ptr);
/*
 * Helper struct for midi events.
 */
typedef struct {
    uint32_t count;
    NativeMidiEvent* events;
} NativeMidiEventsBuffer;
/* ------------------------------------------------------------------------------------------------------------
 * Enums */
enum JackPortFlags {
    JackPortIsInput    = 0x01,
    JackPortIsOutput   = 0x02,
    JackPortIsPhysical = 0x04,
    JackPortCanMonitor = 0x08,
    JackPortIsTerminal = 0x10
};
enum JackOptions {
    JackNullOption    = 0x00,
    JackNoStartServer = 0x01,
    JackUseExactName  = 0x02,
    JackServerName    = 0x04,
    JackLoadName      = 0x08,
    JackLoadInit      = 0x10,
    JackSessionID     = 0x20
};
enum JackStatus {
    JackFailure       = 0x0001,
    JackInvalidOption = 0x0002,
    JackNameNotUnique = 0x0004,
    JackServerStarted = 0x0008,
    JackServerFailed  = 0x0010,
    JackServerError   = 0x0020,
    JackNoSuchClient  = 0x0040,
    JackLoadFailure   = 0x0080,
    JackInitFailure   = 0x0100,
    JackShmFailure    = 0x0200,
    JackVersionError  = 0x0400,
    JackBackendError  = 0x0800,
    JackClientZombie  = 0x1000
};
typedef enum JackOptions jack_options_t;
typedef enum JackStatus  jack_status_t;
/* ------------------------------------------------------------------------------------------------------------
 * Structs */
typedef struct {
    bool  registered;
    bool  isAudio;
    uint  flags;
    union {
        void* audio;
        NativeMidiEventsBuffer midi;
    } buffer;
} jack_port_t;
typedef struct {
    // current state
    bool           active;
    const char*    clientName;
    jack_nframes_t bufferSize;
    jack_nframes_t sampleRate;
    // callbacks
    jack_process_callback processCallback;
    void*                 processPtr;
    // ports
    jack_port_t portsAudioIn [16];
    jack_port_t portsAudioOut[16];
    jack_port_t portsMidiIn  [16];
    jack_port_t portsMidiOut [16];
} jack_client_t;
typedef struct {
  uint32_t time;
  uint32_t size;
  uint8_t* buffer;
} jack_midi_event_t;
/* ------------------------------------------------------------------------------------------------------------
 * Client functions */
/*
 * NOTE: This function purposefully returns NULL, as we *do not* want global variables.
 *       The client pointer is passed into the plugin code directly.
 */
static inline
jack_client_t* jack_client_open(const char* clientname, jack_options_t options, jack_status_t* status, ...)
{
    if (status != NULL)
        *status = JackFailure;
    return NULL;
    // unused
    (void)clientname;
    (void)options;
}
static inline
int jack_client_close(jack_client_t* client)
{
    memset(client, 0, sizeof(jack_client_t));
    return 0;
}
/* ------------------------------------------------------------------------------------------------------------
 * Callback functions */
static inline
int jack_on_shutdown(jack_client_t* client, jack_shutdown_callback callback, void* ptr)
{
    return 0;
    // unused
    (void)client;
    (void)callback;
    (void)ptr;
}
static inline
int jack_set_process_callback(jack_client_t* client, jack_process_callback callback, void* ptr)
{
    client->processCallback = callback;
    client->processPtr      = ptr;
    return 0;
}
/* ------------------------------------------------------------------------------------------------------------
 * Port functions */
static inline
jack_port_t* jack_port_register(jack_client_t* client, const char* name, const char* type, ulong flags, ulong buffersize)
{
    const bool isAudio = strcmp(type, JACK_DEFAULT_AUDIO_TYPE) == 0;
    const bool isMIDI  = strcmp(type, JACK_DEFAULT_MIDI_TYPE ) == 0;
    if (! (isAudio || isMIDI))
        return NULL;
    jack_port_t* ports;
    if (isAudio)
        ports = (flags & JackPortIsInput) ? client->portsAudioIn : client->portsAudioOut;
    else
        ports = (flags & JackPortIsInput) ? client->portsMidiIn : client->portsMidiOut;
    for (int i=0; i<16; ++i)
    {
        jack_port_t* const port = &ports[i];
        if (port->registered)
            continue;
        memset(port, 0, sizeof(jack_port_t));
        port->registered = true;
        port->isAudio    = isAudio;
        port->flags      = flags;
        return port;
    }
    return NULL;
    // unused
    (void)name;
    (void)type;
    (void)buffersize;
}
static inline
int jack_port_unregister(jack_client_t* client, jack_port_t* port)
{
    jack_port_t* const ports = (port->flags & JackPortIsInput) ? client->portsAudioIn : client->portsAudioOut;
    for (int i=0; i<8; ++i)
    {
        if (&ports[i] == port)
        {
            memset(port, 0, sizeof(jack_port_t));
            return 0;
        }
    }
    return 1;
}
static inline
void* jack_port_get_buffer(jack_port_t* port, jack_nframes_t nframes)
{
    return port->isAudio ? port->buffer.audio : &port->buffer.midi;
    // unused
    (void)nframes;
}
/* ------------------------------------------------------------------------------------------------------------
 * MIDI functions */
static inline
uint32_t jack_midi_get_event_count(void* port_buffer)
{
    NativeMidiEventsBuffer* const midi_buffer = (NativeMidiEventsBuffer*)port_buffer;
    return midi_buffer->count;
}
static inline
int jack_midi_event_get(jack_midi_event_t* event, void* port_buffer, uint32_t event_index)
{
    NativeMidiEventsBuffer* const midi_buffer = (NativeMidiEventsBuffer*)port_buffer;
    if (midi_buffer->count == 0)
        return ENODATA;
    if (event_index >= midi_buffer->count)
        return 1; // FIXME
    NativeMidiEvent* const midiEvent = &midi_buffer->events[event_index];
    event->time   = midiEvent->time;
    event->size   = midiEvent->size;
    event->buffer = midiEvent->data;
    return 0;
}
/* ------------------------------------------------------------------------------------------------------------
 * [De/]Activate */
static inline
int jack_activate(jack_client_t* client)
{
    client->active = true;
    return 0;
}
static inline
int jack_deactivate(jack_client_t* client)
{
    client->active = false;
    return 0;
}
/* ------------------------------------------------------------------------------------------------------------
 * Get data functions */
static inline
const char* jack_get_client_name(const jack_client_t* client)
{
    return client->clientName;
}
static inline
jack_nframes_t jack_get_buffer_size(const jack_client_t* client)
{
    return client->bufferSize;
}
static inline
jack_nframes_t jack_get_sample_rate(const jack_client_t* client)
{
    return client->sampleRate;
}
/* ------------------------------------------------------------------------------------------------------------
 * Misc */
static inline
pthread_t jack_client_thread_id(const jack_client_t* client)
{
    return pthread_self();
    // unused
    (void)client;
}
/* ------------------------------------------------------------------------------------------------------------ */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* CARLA_NATIVE_JACK_H_INCLUDED */
 |