<commit_before>/*
  rtjack.c:

  Copyright (C) 2005, 2006 <NAME>

  This file is part of Csound.

  The Csound Library is free software; you can redistribute it
  and/or modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  Csound 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 Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with Csound; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  02111-1307 USA
*/

#include <jack/jack.h>
#include <ctype.h>
/* no #ifdef, should always have these on systems where JACK is available */
#include <unistd.h>
#include <stdint.h>
#ifdef LINUX
#include <pthread.h>
#endif
#include "csdl.h"
#include "soundio.h"
#ifdef LINUX
#include <sched.h>
#endif

#include "cs_jack.h"

#ifdef LINUX

static inline int rtJack_CreateLock(CSOUND *csound, pthread_mutex_t *p)
{
    (void) csound;
    return (pthread_mutex_init(p, (pthread_mutexattr_t*) NULL));
}

static inline void rtJack_Lock(CSOUND *csound, pthread_mutex_t *p)
{
    (void) csound;
    pthread_mutex_lock(p);
}

static inline int rtJack_TryLock(CSOUND *csound, pthread_mutex_t *p)
{
    (void) csound;
    return (pthread_mutex_trylock(p));
}

static inline void rtJack_Unlock(CSOUND *csound, pthread_mutex_t *p)
{
    (void) csound;
    pthread_mutex_unlock(p);
}

static inline void rtJack_DestroyLock(CSOUND *csound, pthread_mutex_t *p)
{
    (void) csound;
    pthread_mutex_unlock(p);
    pthread_mutex_destroy(p);
}

#else   /* LINUX */

static inline int rtJack_CreateLock(CSOUND *csound, void **p)
{
    *p = csound->CreateThreadLock();
    return (*p != NULL ? 0 : -1);
}

static inline void rtJack_Lock(CSOUND *csound, void **p)
{
    csound->WaitThreadLockNoTimeout(*p);
}

static inline int rtJack_TryLock(CSOUND *csound, void **p)
{
    return (csound->WaitThreadLock(*p, (size_t) 0));
}

static inline void rtJack_Unlock(CSOUND *csound, void **p)
{
    csound->NotifyThreadLock(*p);
}

static inline void rtJack_DestroyLock(CSOUND *csound, void **p)
{
    csound->NotifyThreadLock(*p);
    csound->DestroyThreadLock(*p);
    *p = NULL;
}

#endif  /* !LINUX */

/* print error message, close connection, and terminate performance */

static CS_NORETURN void rtJack_Error(CSOUND *, int errCode, const char *msg);

static int processCallback(jack_nframes_t nframes, void *arg);

/* callback functions */

static int sampleRateCallback(jack_nframes_t nframes, void *arg)
{
    RtJackGlobals *p = (RtJackGlobals*) arg;

    if (p->sampleRate != (int) nframes)
      p->jackState = 1;
    return 0;
}

static int bufferSizeCallback(jack_nframes_t nframes, void *arg)
{
    RtJackGlobals *p = (RtJackGlobals*) arg;

    (void) nframes;
    /* invalidate output port buffer pointer cache */
    if (p->outPortBufs != NULL)
      p->outPortBufs[0] = (jack_default_audio_sample_t*) NULL;
    return 0;
}

#ifdef LINUX
static void freeWheelCallback(int starting, void *arg)
{
    RtJackGlobals *p;
    CSOUND *csound;

    p = (RtJackGlobals*) arg;
    csound = p->csound;
    if (starting) {
      if (UNLIKELY(sched_getscheduler(0) != SCHED_OTHER)) {
        struct sched_param sp;
        csound->Message(csound, Str(" *** WARNING: "
                                    "disabling --sched in freewheel mode\n"));
        memset(&sp, 0, sizeof(struct sched_param));
        sp.sched_priority = 0;
        sched_setscheduler(0, SCHED_OTHER, &sp);
      }
    }
}
#endif

static int xrunCallback(void *arg)
{
    RtJackGlobals *p = (RtJackGlobals*) arg;

    p->xrunFlag = 1;
    return 0;
}

static void shutDownCallback(void *arg)
{
    RtJackGlobals *p = (RtJackGlobals*) arg;

    p->jackState = 2;
    if (p->bufs != NULL) {
      int   i;
      for (i = 0; i < p->nBuffers; i++) {
        if (p->bufs[i] != NULL &&
            (p->bufs[i]->inBufs != NULL || p->bufs[i]->outBufs != NULL))
          rtJack_Unlock(p->csound, &(p->bufs[i]->csndLock));
      }
    }
}

static CS_NOINLINE void rtJack_PrintPortName(CSOUND *csound,
                                             const char *portName,
                                             int nChannels)
{
    if (nChannels > 0 && portName[0] != (char) 0) {
      if ((int) strlen(portName) < 16)
        csound->Message(csound, "      \"%s\"\t\t", portName);
      else
        csound->Message(csound, "      \"%s\"\t", portName);
      if (nChannels > 1)
        csound->Message(csound, Str("(%d channels)\n"), nChannels);
      else
        csound->Message(csound, Str("(1 channel)\n"));
    }
}

static int portname_cmp_func(const void *p1, const void *p2)
{
    return (strcmp(*((char**) p1), *((char**) p2)));
}

/* Print the list of available device names for -i adc (if isOutput is zero) */
/* or -o dac, returning zero on success. */

static CS_NOINLINE int rtJack_ListPorts(CSOUND *csound,
                                        jack_client_t *jackClient,
                                        const char *clientName,
                                        int isOutput)
{
    char            **portNames = (char**) NULL;
    char            clientNameBuf[MAX_NAME_LEN + 2];
    char            *prvPortName = (char*) NULL, *curPortName = (char*) NULL;
    unsigned long   portFlags;
    int             i, nChn, maxChn, len, nPorts, retval = -1;

    portFlags = (isOutput ? (unsigned long) JackPortIsInput
                 : (unsigned long) JackPortIsOutput);
    len = jack_port_name_size();
    prvPortName = (char*) malloc((size_t) len);
    if (UNLIKELY(prvPortName == (char*) NULL))
      goto err_return;
    curPortName = (char*) malloc((size_t) len);
    if (UNLIKELY(curPortName == (char*) NULL))
      goto err_return;
    portNames = (char**) jack_get_ports(jackClient,
                                        (char*) NULL,
                                        JACK_DEFAULT_AUDIO_TYPE,
                                        portFlags);
    if (UNLIKELY(portNames == (char**) NULL))
      goto err_return;
    retval = 0;
    csound->Message(csound, Str("The available JACK %s devices are:\n"),
                    (isOutput ? Str("output") : Str("input")));
    /* count the number of ports, and sort port names in alphabetical order */
    for (nPorts = 0; portNames[nPorts] != NULL; nPorts++)
      ;
    qsort((void*) portNames, (size_t) nPorts, sizeof(char*), portname_cmp_func);
    sprintf(&(clientNameBuf[0]), "%s:", clientName);
    len = strlen(&(clientNameBuf[0]));
    prvPortName[0] = (char) 0;
    maxChn = nChn = 0;
    for (i = 0; portNames[i] != NULL; i++) {
      int     n, chn_;
      /* skip ports owned by this client */
      if (strncmp(portNames[i], &(clientNameBuf[0]), (size_t) len) == 0)
        goto nextPortName;
      n = (int) strlen(portNames[i]);
      do {
        n--;
      } while (n > 0 && isdigit(portNames[i][n]));
      n++;
      if (n < 2 || n == (int) strlen(portNames[i]))
        goto nextPortName;
      chn_ = (int) atoi(&(portNames[i][n]));
      if (chn_ == 0)
        goto nextPortName;
      strncpy(curPortName, portNames[i], (size_t) n);
      curPortName[n] = (char) 0;
      if (strcmp(curPortName, prvPortName) != 0) {
        if (nChn == maxChn)
          rtJack_PrintPortName(csound, prvPortName, nChn);
        strcpy(prvPortName, curPortName);
        nChn = 1;
        maxChn = chn_;
      }
      else {
        nChn++;
        if (chn_ > maxChn)
          maxChn = chn_;
      }
      continue;
    nextPortName:
      if (nChn == maxChn)
        rtJack_PrintPortName(csound, prvPortName, nChn);
      prvPortName[0] = (char) 0;
      maxChn = nChn = 0;
    }
    if (nChn == maxChn)
      rtJack_PrintPortName(csound, prvPortName, nChn);

 err_return:
    if (portNames != (char**) NULL)
      free((void*) portNames);
    if (curPortName != (char*) NULL)
      free((void*) curPortName);
    if (prvPortName != (char*) NULL)
      free((void*) prvPortName);
    return retval;
}

static inline size_t rtJack_AlignData(size_t ofs)
{
    return ((ofs + (size_t) 15) & (~((size_t) 15)));
}

/* allocate ring buffers */

static void rtJack_AllocateBuffers(RtJackGlobals *p)
{
    CSOUND *csound = p->csound;
    void    *ptr;
    size_t  i, j, m, nBytes, nBytesPerBuf, ofs1, ofs2, ofs3;

    m = (size_t) ((p->inputEnabled ? 1 : 0) + (p->outputEnabled ? 1 : 0));
    if (!m)
      return;
    /* calculate the number of bytes to allocate */
    ofs1 = rtJack_AlignData(sizeof(RtJackBuffer*) * (size_t) p->nBuffers);
    ofs2 = rtJack_AlignData(sizeof(RtJackBuffer));
    ofs3 = rtJack_AlignData(sizeof(jack_default_audio_sample_t*)
                            * (size_t) p->nChannels * m);
    nBytesPerBuf = ofs2 + ofs3;
    nBytesPerBuf += rtJack_AlignData(sizeof(jack_default_audio_sample_t)
                                     * (size_t) p->nChannels
                                     * (size_t) p->bufSize
                                     * m);
    nBytes = ofs1 + (nBytesPerBuf * (size_t) p->nBuffers);
    /* allocate memory */
    ptr = (RtJackBuffer**) malloc(nBytes);
    if (UNLIKELY(ptr == NULL))
      rtJack_Error(csound, CSOUND_MEMORY, Str("memory allocation failure"));
    p->bufs = (RtJackBuffer**) ptr;
    memset((void*) ptr, 0, nBytes);
    /* set pointer to each buffer */
    ptr = (void*) ((char*) ptr + (long) ofs1);
    for (i = (size_t) 0; i < (size_t) p->nBuffers; i++) {
      p->bufs[i] = ptr;
      ptr = (void*) ((char*) ptr + (long) nBytesPerBuf);
    }
    for (i = (size_t) 0; i < (size_t) p->nBuffers; i++) {
      /* create lock for signaling when the process callback is done */
      /* with the buffer */
      if (UNLIKELY(rtJack_CreateLock(csound, &(p->bufs[i]->csndLock)) != 0))
        rtJack_Error(csound, CSOUND_MEMORY, Str("memory allocation failure"));
      /* create lock for signaling when the Csound thread is done */
      /* with the buffer */
      if (UNLIKELY(rtJack_CreateLock(csound, &(p->bufs[i]->jackLock)) != 0)) {
        rtJack_DestroyLock(csound, &(p->bufs[i]->csndLock));
        rtJack_Error(csound, CSOUND_MEMORY, Str("memory allocation failure"));
      }
      ptr = (void*) p->bufs[i];
      ptr = (void*) ((char*) ptr + (long) ofs2);
      /* set pointers to input/output buffers */
      if (p->inputEnabled) {
        p->bufs[i]->inBufs = (jack_default_audio_sample_t**) ptr;
        ptr = (void*) &(p->bufs[i]->inBufs[p->nChannels]);
      }
      if (p->outputEnabled)
        p->bufs[i]->outBufs = (jack_default_audio_sample_t**) ptr;
      ptr = (void*) p->bufs[i];
      ptr = (void*) ((char*) ptr + (long) (ofs2 + ofs3));
      for (j = (size_t) 0; j < (size_t) p->nChannels; j++) {
        if (p->inputEnabled) {
          p->bufs[i]->inBufs[j] = (jack_default_audio_sample_t*) ptr;
          ptr = (void*) &(p->bufs[i]->inBufs[j][p->bufSize]);
        }
        if (p->outputEnabled) {
          p->bufs[i]->outBufs[j] = (jack_default_audio_sample_t*) ptr;
          ptr = (void*) &(p->bufs[i]->outBufs[j][p->bufSize]);
        }
      }
    }
}

/* register JACK ports */

static void rtJack_RegisterPorts(RtJackGlobals *p)
{
    char          portName[MAX_NAME_LEN + 4];
    unsigned long flags = 0UL;
    int           i;
    CSOUND *csound = p->csound;

    if (!(p->inputEnabled && p->outputEnabled))
      flags = (unsigned long) JackPortIsTerminal;
    if (p->inputEnabled) {
      /* register input ports */
      for (i = 0; i < p->nChannels; i++) {
        sprintf(&(portName[0]), "%s%d", &(p->inputPortName[0]), i + 1);
        p->inPorts[i] = jack_port_register(p->client, &(portName[0]),
                                           JACK_DEFAULT_AUDIO_TYPE,
                                           flags | JackPortIsInput, 0UL);
        if (UNLIKELY(p->inPorts[i] == NULL))
          rtJack_Error(csound, -1, Str("error registering input ports"));
      }
    }
    if (p->outputEnabled) {
      /* register output ports */
      for (i = 0; i < p->nChannels; i++) {
        sprintf(&(portName[0]), "%s%d", &(p->outputPortName[0]), i + 1);
        p->outPorts[i] = jack_port_register(p->client, &(portName[0]),
                                            JACK_DEFAULT_AUDIO_TYPE,
                                            flags | JackPortIsOutput, 0UL);
        if (UNLIKELY(p->outPorts[i] == NULL))
          rtJack_Error(csound, -1, Str("error registering output ports"));
      }
    }
}
static int listDevices(CSOUND *csound, CS_AUDIODEVICE *list, int isOutput);
/* connect to JACK server, set up ports and ring buffers, */
/* activate client, and connect ports if requested */

static void openJackStreams(RtJackGlobals *p)
{
    char    buf[256];
    int     i, j, k;
    CSOUND *csound = p->csound;

    /* connect to JACK server */
    p->client = jack_client_open(&(p->clientName[0]), JackNullOption, NULL);
    if (UNLIKELY(p->client == NULL))
      rtJack_Error(csound, -1, Str("could not connect to JACK server"));

    /* check consistency of parameters */
    if (UNLIKELY(p->nChannels < 1 || p->nChannels > 255))
      rtJack_Error(csound, -1, Str("invalid number of channels"));
    if (UNLIKELY(p->sampleRate < 1000 || p->sampleRate > 768000))
      rtJack_Error(csound, -1, Str("invalid sample rate"));
    if (UNLIKELY(p->sampleRate != (int) jack_get_sample_rate(p->client))) {
      sprintf(&(buf[0]), Str("sample rate %d does not match "
                             "JACK sample rate %d"),
              p->sampleRate, (int) jack_get_sample_rate(p->client));
      rtJack_Error(p->csound, -1, &(buf[0]));
    }
    if (UNLIKELY(p->bufSize < 8 || p->bufSize > 32768))
      rtJack_Error(csound, -1, Str("invalid period size (-b)"));
    if (p->nBuffers < 2)
      p->nBuffers = 2;
    if (UNLIKELY((unsigned int) (p->nBuffers * p->bufSize) > (unsigned int) 65536))
      rtJack_Error(csound, -1, Str("invalid buffer size (-B)"));
    if (UNLIKELY(((p->nBuffers - 1) * p->bufSize)
                 < (int) jack_get_buffer_size(p->client)))
      rtJack_Error(csound, -1, Str("buffer size (-B) is too small"));

    /* register ports */
    rtJack_RegisterPorts(p);

    /* allocate ring buffers if not done yet */
    if (p->bufs == NULL)
      rtJack_AllocateBuffers(p);

    /* initialise ring buffers */
    p->csndBufCnt = 0;
    p->csndBufPos = 0;
    p->jackBufCnt = 0;
    p->jackBufPos = 0;
    for (i = 0; i < p->nBuffers; i++) {
      rtJack_TryLock(p->csound, &(p->bufs[i]->csndLock));
      rtJack_Unlock(p->csound, &(p->bufs[i]->jackLock));
      for (j = 0; j < p->nChannels; j++) {
        if (p->inputEnabled) {
          for (k = 0; k < p->bufSize; k++)
            p->bufs[i]->inBufs[j][k] = (jack_default_audio_sample_t) 0;
        }
        if (p->outputEnabled) {
          for (k = 0; k < p->bufSize; k++)
            p->bufs[i]->outBufs[j][k] = (jack_default_audio_sample_t) 0;
        }
      }
    }

    /* output port buffer pointer cache is invalid initially */
    if (p->outputEnabled)
      p->outPortBufs[0] = (jack_default_audio_sample_t*) NULL;

    /* register callback functions */
    if (UNLIKELY(jack_set_sample_rate_callback(p->client,
                                               sampleRateCallback, (void*) p)
                 != 0))
      rtJack_Error(csound, -1, Str("error setting sample rate callback"));
    if (UNLIKELY(jack_set_buffer_size_callback(p->client,
                                               bufferSizeCallback, (void*) p)
                 != 0))
      rtJack_Error(csound, -1, Str("error setting buffer size callback"));
#ifdef LINUX
    if (UNLIKELY(jack_set_freewheel_callback(p->client,
                                             freeWheelCallback, (void*) p)
                 != 0))
      rtJack_Error(csound, -1, Str("error setting freewheel callback"));
#endif
    if (UNLIKELY(jack_set_xrun_callback(p->client, xrunCallback, (void*) p) != 0))
      rtJack_Error(csound, -1, Str("error setting xrun callback"));
    jack_on_shutdown(p->client, shutDownCallback, (void*) p);
    if (UNLIKELY(jack_set_process_callback(p->client,
                                           processCallback, (void*) p) != 0))
      rtJack_Error(csound, -1, Str("error setting process callback"));

    /* activate client */
    if (UNLIKELY(jack_activate(p->client) != 0))
      rtJack_Error(csound, -1, Str("error activating JACK client"));

    /* connect ports if requested */
    if (p->inputEnabled) {
      char dev[128], *sp;
      {
        int i,n = listDevices(csound,NULL,0);
        CS_AUDIODEVICE *devs = (CS_AUDIODEVICE *)
                malloc(n*sizeof(CS_AUDIODEVICE));
        listDevices(csound,devs,0);
        for(i=0; i < n; i++)
          csound->Message(csound, " %d: %s (%s)\n",
                          i, devs[i].device_id, devs[i].device_name);
        strncpy(dev, devs[0].device_name, 128);
        free(devs);
      }
      if(p->inDevName != NULL)
          strncpy(dev, p->inDevName, 128);

      if (dev) {
        sp = strchr(dev, '\0');
//        if(!isalpha(dev[0])) dev++;

        for (i = 0; i < p->nChannels; i++) {
          sprintf(sp, "%d", i + 1);
          if (UNLIKELY(jack_connect(p->client, dev,
                                    jack_port_name(p->inPorts[i])) != 0)) {
              rtJack_Error(csound, -1, Str("error connecting input ports"));
          }
        }
        *sp = (char) 0;
      }
    }
    if (p->outputEnabled) {
      char dev[128], *sp;
      {
          int i,n = listDevices(csound,NULL,1);
          CS_AUDIODEVICE *devs = (CS_AUDIODEVICE *)
                  malloc(n*sizeof(CS_AUDIODEVICE));
          listDevices(csound,devs,1);
          for(i=0; i < n; i++)
            csound->Message(csound, " %d: %s (%s)\n",
                            i, devs[i].device_id, devs[i].device_name);
          strncpy(dev, devs[0].device_name, 128);
          free(devs);
      }
      if(p->outDevName != NULL) strncpy(dev, p->outDevName, 128);
      if (dev) {
        sp = strchr(dev, '\0');
//        if(!isalpha(dev[0])) dev++;
        for (i = 0; i < p->nChannels; i++) {
          sprintf(sp, "%d", i + 1);
          if (jack_connect(p->client, jack_port_name(p->outPorts[i]), dev) != 0) {
            rtJack_Error(csound, -1, Str("error connecting output ports"));
          }
        }
        *sp = (char) 0;
      }
    }<commit_msg>Put back discarding non alpha characters in jack device names<commit_after>/*
  rtjack.c:

  Copyright (C) 2005, 2006 <NAME>

  This file is part of Csound.

  The Csound Library is free software; you can redistribute it
  and/or modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  Csound 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 Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with Csound; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  02111-1307 USA
*/

#include <jack/jack.h>
#include <ctype.h>
/* no #ifdef, should always have these on systems where JACK is available */
#include <unistd.h>
#include <stdint.h>
#ifdef LINUX
#include <pthread.h>
#endif
#include "csdl.h"
#include "soundio.h"
#ifdef LINUX
#include <sched.h>
#endif

#include "cs_jack.h"

#ifdef LINUX

static inline int rtJack_CreateLock(CSOUND *csound, pthread_mutex_t *p)
{
    (void) csound;
    return (pthread_mutex_init(p, (pthread_mutexattr_t*) NULL));
}

static inline void rtJack_Lock(CSOUND *csound, pthread_mutex_t *p)
{
    (void) csound;
    pthread_mutex_lock(p);
}

static inline int rtJack_TryLock(CSOUND *csound, pthread_mutex_t *p)
{
    (void) csound;
    return (pthread_mutex_trylock(p));
}

static inline void rtJack_Unlock(CSOUND *csound, pthread_mutex_t *p)
{
    (void) csound;
    pthread_mutex_unlock(p);
}

static inline void rtJack_DestroyLock(CSOUND *csound, pthread_mutex_t *p)
{
    (void) csound;
    pthread_mutex_unlock(p);
    pthread_mutex_destroy(p);
}

#else   /* LINUX */

static inline int rtJack_CreateLock(CSOUND *csound, void **p)
{
    *p = csound->CreateThreadLock();
    return (*p != NULL ? 0 : -1);
}

static inline void rtJack_Lock(CSOUND *csound, void **p)
{
    csound->WaitThreadLockNoTimeout(*p);
}

static inline int rtJack_TryLock(CSOUND *csound, void **p)
{
    return (csound->WaitThreadLock(*p, (size_t) 0));
}

static inline void rtJack_Unlock(CSOUND *csound, void **p)
{
    csound->NotifyThreadLock(*p);
}

static inline void rtJack_DestroyLock(CSOUND *csound, void **p)
{
    csound->NotifyThreadLock(*p);
    csound->DestroyThreadLock(*p);
    *p = NULL;
}

#endif  /* !LINUX */

/* print error message, close connection, and terminate performance */

static CS_NORETURN void rtJack_Error(CSOUND *, int errCode, const char *msg);

static int processCallback(jack_nframes_t nframes, void *arg);

/* callback functions */

static int sampleRateCallback(jack_nframes_t nframes, void *arg)
{
    RtJackGlobals *p = (RtJackGlobals*) arg;

    if (p->sampleRate != (int) nframes)
      p->jackState = 1;
    return 0;
}

static int bufferSizeCallback(jack_nframes_t nframes, void *arg)
{
    RtJackGlobals *p = (RtJackGlobals*) arg;

    (void) nframes;
    /* invalidate output port buffer pointer cache */
    if (p->outPortBufs != NULL)
      p->outPortBufs[0] = (jack_default_audio_sample_t*) NULL;
    return 0;
}

#ifdef LINUX
static void freeWheelCallback(int starting, void *arg)
{
    RtJackGlobals *p;
    CSOUND *csound;

    p = (RtJackGlobals*) arg;
    csound = p->csound;
    if (starting) {
      if (UNLIKELY(sched_getscheduler(0) != SCHED_OTHER)) {
        struct sched_param sp;
        csound->Message(csound, Str(" *** WARNING: "
                                    "disabling --sched in freewheel mode\n"));
        memset(&sp, 0, sizeof(struct sched_param));
        sp.sched_priority = 0;
        sched_setscheduler(0, SCHED_OTHER, &sp);
      }
    }
}
#endif

static int xrunCallback(void *arg)
{
    RtJackGlobals *p = (RtJackGlobals*) arg;

    p->xrunFlag = 1;
    return 0;
}

static void shutDownCallback(void *arg)
{
    RtJackGlobals *p = (RtJackGlobals*) arg;

    p->jackState = 2;
    if (p->bufs != NULL) {
      int   i;
      for (i = 0; i < p->nBuffers; i++) {
        if (p->bufs[i] != NULL &&
            (p->bufs[i]->inBufs != NULL || p->bufs[i]->outBufs != NULL))
          rtJack_Unlock(p->csound, &(p->bufs[i]->csndLock));
      }
    }
}

static CS_NOINLINE void rtJack_PrintPortName(CSOUND *csound,
                                             const char *portName,
                                             int nChannels)
{
    if (nChannels > 0 && portName[0] != (char) 0) {
      if ((int) strlen(portName) < 16)
        csound->Message(csound, "      \"%s\"\t\t", portName);
      else
        csound->Message(csound, "      \"%s\"\t", portName);
      if (nChannels > 1)
        csound->Message(csound, Str("(%d channels)\n"), nChannels);
      else
        csound->Message(csound, Str("(1 channel)\n"));
    }
}

static int portname_cmp_func(const void *p1, const void *p2)
{
    return (strcmp(*((char**) p1), *((char**) p2)));
}

/* Print the list of available device names for -i adc (if isOutput is zero) */
/* or -o dac, returning zero on success. */

static CS_NOINLINE int rtJack_ListPorts(CSOUND *csound,
                                        jack_client_t *jackClient,
                                        const char *clientName,
                                        int isOutput)
{
    char            **portNames = (char**) NULL;
    char            clientNameBuf[MAX_NAME_LEN + 2];
    char            *prvPortName = (char*) NULL, *curPortName = (char*) NULL;
    unsigned long   portFlags;
    int             i, nChn, maxChn, len, nPorts, retval = -1;

    portFlags = (isOutput ? (unsigned long) JackPortIsInput
                 : (unsigned long) JackPortIsOutput);
    len = jack_port_name_size();
    prvPortName = (char*) malloc((size_t) len);
    if (UNLIKELY(prvPortName == (char*) NULL))
      goto err_return;
    curPortName = (char*) malloc((size_t) len);
    if (UNLIKELY(curPortName == (char*) NULL))
      goto err_return;
    portNames = (char**) jack_get_ports(jackClient,
                                        (char*) NULL,
                                        JACK_DEFAULT_AUDIO_TYPE,
                                        portFlags);
    if (UNLIKELY(portNames == (char**) NULL))
      goto err_return;
    retval = 0;
    csound->Message(csound, Str("The available JACK %s devices are:\n"),
                    (isOutput ? Str("output") : Str("input")));
    /* count the number of ports, and sort port names in alphabetical order */
    for (nPorts = 0; portNames[nPorts] != NULL; nPorts++)
      ;
    qsort((void*) portNames, (size_t) nPorts, sizeof(char*), portname_cmp_func);
    sprintf(&(clientNameBuf[0]), "%s:", clientName);
    len = strlen(&(clientNameBuf[0]));
    prvPortName[0] = (char) 0;
    maxChn = nChn = 0;
    for (i = 0; portNames[i] != NULL; i++) {
      int     n, chn_;
      /* skip ports owned by this client */
      if (strncmp(portNames[i], &(clientNameBuf[0]), (size_t) len) == 0)
        goto nextPortName;
      n = (int) strlen(portNames[i]);
      do {
        n--;
      } while (n > 0 && isdigit(portNames[i][n]));
      n++;
      if (n < 2 || n == (int) strlen(portNames[i]))
        goto nextPortName;
      chn_ = (int) atoi(&(portNames[i][n]));
      if (chn_ == 0)
        goto nextPortName;
      strncpy(curPortName, portNames[i], (size_t) n);
      curPortName[n] = (char) 0;
      if (strcmp(curPortName, prvPortName) != 0) {
        if (nChn == maxChn)
          rtJack_PrintPortName(csound, prvPortName, nChn);
        strcpy(prvPortName, curPortName);
        nChn = 1;
        maxChn = chn_;
      }
      else {
        nChn++;
        if (chn_ > maxChn)
          maxChn = chn_;
      }
      continue;
    nextPortName:
      if (nChn == maxChn)
        rtJack_PrintPortName(csound, prvPortName, nChn);
      prvPortName[0] = (char) 0;
      maxChn = nChn = 0;
    }
    if (nChn == maxChn)
      rtJack_PrintPortName(csound, prvPortName, nChn);

 err_return:
    if (portNames != (char**) NULL)
      free((void*) portNames);
    if (curPortName != (char*) NULL)
      free((void*) curPortName);
    if (prvPortName != (char*) NULL)
      free((void*) prvPortName);
    return retval;
}

static inline size_t rtJack_AlignData(size_t ofs)
{
    return ((ofs + (size_t) 15) & (~((size_t) 15)));
}

/* allocate ring buffers */

static void rtJack_AllocateBuffers(RtJackGlobals *p)
{
    CSOUND *csound = p->csound;
    void    *ptr;
    size_t  i, j, m, nBytes, nBytesPerBuf, ofs1, ofs2, ofs3;

    m = (size_t) ((p->inputEnabled ? 1 : 0) + (p->outputEnabled ? 1 : 0));
    if (!m)
      return;
    /* calculate the number of bytes to allocate */
    ofs1 = rtJack_AlignData(sizeof(RtJackBuffer*) * (size_t) p->nBuffers);
    ofs2 = rtJack_AlignData(sizeof(RtJackBuffer));
    ofs3 = rtJack_AlignData(sizeof(jack_default_audio_sample_t*)
                            * (size_t) p->nChannels * m);
    nBytesPerBuf = ofs2 + ofs3;
    nBytesPerBuf += rtJack_AlignData(sizeof(jack_default_audio_sample_t)
                                     * (size_t) p->nChannels
                                     * (size_t) p->bufSize
                                     * m);
    nBytes = ofs1 + (nBytesPerBuf * (size_t) p->nBuffers);
    /* allocate memory */
    ptr = (RtJackBuffer**) malloc(nBytes);
    if (UNLIKELY(ptr == NULL))
      rtJack_Error(csound, CSOUND_MEMORY, Str("memory allocation failure"));
    p->bufs = (RtJackBuffer**) ptr;
    memset((void*) ptr, 0, nBytes);
    /* set pointer to each buffer */
    ptr = (void*) ((char*) ptr + (long) ofs1);
    for (i = (size_t) 0; i < (size_t) p->nBuffers; i++) {
      p->bufs[i] = ptr;
      ptr = (void*) ((char*) ptr + (long) nBytesPerBuf);
    }
    for (i = (size_t) 0; i < (size_t) p->nBuffers; i++) {
      /* create lock for signaling when the process callback is done */
      /* with the buffer */
      if (UNLIKELY(rtJack_CreateLock(csound, &(p->bufs[i]->csndLock)) != 0))
        rtJack_Error(csound, CSOUND_MEMORY, Str("memory allocation failure"));
      /* create lock for signaling when the Csound thread is done */
      /* with the buffer */
      if (UNLIKELY(rtJack_CreateLock(csound, &(p->bufs[i]->jackLock)) != 0)) {
        rtJack_DestroyLock(csound, &(p->bufs[i]->csndLock));
        rtJack_Error(csound, CSOUND_MEMORY, Str("memory allocation failure"));
      }
      ptr = (void*) p->bufs[i];
      ptr = (void*) ((char*) ptr + (long) ofs2);
      /* set pointers to input/output buffers */
      if (p->inputEnabled) {
        p->bufs[i]->inBufs = (jack_default_audio_sample_t**) ptr;
        ptr = (void*) &(p->bufs[i]->inBufs[p->nChannels]);
      }
      if (p->outputEnabled)
        p->bufs[i]->outBufs = (jack_default_audio_sample_t**) ptr;
      ptr = (void*) p->bufs[i];
      ptr = (void*) ((char*) ptr + (long) (ofs2 + ofs3));
      for (j = (size_t) 0; j < (size_t) p->nChannels; j++) {
        if (p->inputEnabled) {
          p->bufs[i]->inBufs[j] = (jack_default_audio_sample_t*) ptr;
          ptr = (void*) &(p->bufs[i]->inBufs[j][p->bufSize]);
        }
        if (p->outputEnabled) {
          p->bufs[i]->outBufs[j] = (jack_default_audio_sample_t*) ptr;
          ptr = (void*) &(p->bufs[i]->outBufs[j][p->bufSize]);
        }
      }
    }
}

/* register JACK ports */

static void rtJack_RegisterPorts(RtJackGlobals *p)
{
    char          portName[MAX_NAME_LEN + 4];
    unsigned long flags = 0UL;
    int           i;
    CSOUND *csound = p->csound;

    if (!(p->inputEnabled && p->outputEnabled))
      flags = (unsigned long) JackPortIsTerminal;
    if (p->inputEnabled) {
      /* register input ports */
      for (i = 0; i < p->nChannels; i++) {
        sprintf(&(portName[0]), "%s%d", &(p->inputPortName[0]), i + 1);
        p->inPorts[i] = jack_port_register(p->client, &(portName[0]),
                                           JACK_DEFAULT_AUDIO_TYPE,
                                           flags | JackPortIsInput, 0UL);
        if (UNLIKELY(p->inPorts[i] == NULL))
          rtJack_Error(csound, -1, Str("error registering input ports"));
      }
    }
    if (p->outputEnabled) {
      /* register output ports */
      for (i = 0; i < p->nChannels; i++) {
        sprintf(&(portName[0]), "%s%d", &(p->outputPortName[0]), i + 1);
        p->outPorts[i] = jack_port_register(p->client, &(portName[0]),
                                            JACK_DEFAULT_AUDIO_TYPE,
                                            flags | JackPortIsOutput, 0UL);
        if (UNLIKELY(p->outPorts[i] == NULL))
          rtJack_Error(csound, -1, Str("error registering output ports"));
      }
    }
}
static int listDevices(CSOUND *csound, CS_AUDIODEVICE *list, int isOutput);
/* connect to JACK server, set up ports and ring buffers, */
/* activate client, and connect ports if requested */

static void openJackStreams(RtJackGlobals *p)
{
    char    buf[256];
    int     i, j, k;
    CSOUND *csound = p->csound;

    /* connect to JACK server */
    p->client = jack_client_open(&(p->clientName[0]), JackNullOption, NULL);
    if (UNLIKELY(p->client == NULL))
      rtJack_Error(csound, -1, Str("could not connect to JACK server"));

    /* check consistency of parameters */
    if (UNLIKELY(p->nChannels < 1 || p->nChannels > 255))
      rtJack_Error(csound, -1, Str("invalid number of channels"));
    if (UNLIKELY(p->sampleRate < 1000 || p->sampleRate > 768000))
      rtJack_Error(csound, -1, Str("invalid sample rate"));
    if (UNLIKELY(p->sampleRate != (int) jack_get_sample_rate(p->client))) {
      sprintf(&(buf[0]), Str("sample rate %d does not match "
                             "JACK sample rate %d"),
              p->sampleRate, (int) jack_get_sample_rate(p->client));
      rtJack_Error(p->csound, -1, &(buf[0]));
    }
    if (UNLIKELY(p->bufSize < 8 || p->bufSize > 32768))
      rtJack_Error(csound, -1, Str("invalid period size (-b)"));
    if (p->nBuffers < 2)
      p->nBuffers = 2;
    if (UNLIKELY((unsigned int) (p->nBuffers * p->bufSize) > (unsigned int) 65536))
      rtJack_Error(csound, -1, Str("invalid buffer size (-B)"));
    if (UNLIKELY(((p->nBuffers - 1) * p->bufSize)
                 < (int) jack_get_buffer_size(p->client)))
      rtJack_Error(csound, -1, Str("buffer size (-B) is too small"));

    /* register ports */
    rtJack_RegisterPorts(p);

    /* allocate ring buffers if not done yet */
    if (p->bufs == NULL)
      rtJack_AllocateBuffers(p);

    /* initialise ring buffers */
    p->csndBufCnt = 0;
    p->csndBufPos = 0;
    p->jackBufCnt = 0;
    p->jackBufPos = 0;
    for (i = 0; i < p->nBuffers; i++) {
      rtJack_TryLock(p->csound, &(p->bufs[i]->csndLock));
      rtJack_Unlock(p->csound, &(p->bufs[i]->jackLock));
      for (j = 0; j < p->nChannels; j++) {
        if (p->inputEnabled) {
          for (k = 0; k < p->bufSize; k++)
            p->bufs[i]->inBufs[j][k] = (jack_default_audio_sample_t) 0;
        }
        if (p->outputEnabled) {
          for (k = 0; k < p->bufSize; k++)
            p->bufs[i]->outBufs[j][k] = (jack_default_audio_sample_t) 0;
        }
      }
    }

    /* output port buffer pointer cache is invalid initially */
    if (p->outputEnabled)
      p->outPortBufs[0] = (jack_default_audio_sample_t*) NULL;

    /* register callback functions */
    if (UNLIKELY(jack_set_sample_rate_callback(p->client,
                                               sampleRateCallback, (void*) p)
                 != 0))
      rtJack_Error(csound, -1, Str("error setting sample rate callback"));
    if (UNLIKELY(jack_set_buffer_size_callback(p->client,
                                               bufferSizeCallback, (void*) p)
                 != 0))
      rtJack_Error(csound, -1, Str("error setting buffer size callback"));
#ifdef LINUX
    if (UNLIKELY(jack_set_freewheel_callback(p->client,
                                             freeWheelCallback, (void*) p)
                 != 0))
      rtJack_Error(csound, -1, Str("error setting freewheel callback"));
#endif
    if (UNLIKELY(jack_set_xrun_callback(p->client, xrunCallback, (void*) p) != 0))
      rtJack_Error(csound, -1, Str("error setting xrun callback"));
    jack_on_shutdown(p->client, shutDownCallback, (void*) p);
    if (UNLIKELY(jack_set_process_callback(p->client,
                                           processCallback, (void*) p) != 0))
      rtJack_Error(csound, -1, Str("error setting process callback"));

    /* activate client */
    if (UNLIKELY(jack_activate(p->client) != 0))
      rtJack_Error(csound, -1, Str("error activating JACK client"));

    /* connect ports if requested */
    if (p->inputEnabled) {
      char dev[128], *dev_final, *sp;
      {
        int i,n = listDevices(csound,NULL,0);
        CS_AUDIODEVICE *devs = (CS_AUDIODEVICE *)
                malloc(n*sizeof(CS_AUDIODEVICE));
        listDevices(csound,devs,0);
        for(i=0; i < n; i++)
          csound->Message(csound, " %d: %s (%s)\n",
                          i, devs[i].device_id, devs[i].device_name);
        strncpy(dev, devs[0].device_name, 128);
        free(devs);
      }
      if(p->inDevName != NULL)
          strncpy(dev, p->inDevName, 128);

      if (dev) {
        dev_final = dev;
        sp = strchr(dev_final, '\0');
        if(!isalpha(dev_final[0])) dev_final++;

        for (i = 0; i < p->nChannels; i++) {
          sprintf(sp, "%d", i + 1);
          if (UNLIKELY(jack_connect(p->client, dev_final,
                                    jack_port_name(p->inPorts[i])) != 0)) {
              rtJack_Error(csound, -1, Str("error connecting input ports"));
          }
        }
        *sp = (char) 0;
      }
    }
    if (p->outputEnabled) {
      char dev[128], *dev_final, *sp;
      {
          int i,n = listDevices(csound,NULL,1);
          CS_AUDIODEVICE *devs = (CS_AUDIODEVICE *)
                  malloc(n*sizeof(CS_AUDIODEVICE));
          listDevices(csound,devs,1);
          for(i=0; i < n; i++)
            csound->Message(csound, " %d: %s (%s)\n",
                            i, devs[i].device_id, devs[i].device_name);
          strncpy(dev, devs[0].device_name, 128);
          free(devs);
      }
      if(p->outDevName != NULL) strncpy(dev, p->outDevName, 128);
      if (dev) {
        dev_final = dev;
        sp = strchr(dev_final, '\0');
        if(!isalpha(dev_final[0])) dev_final++;
        for (i = 0; i < p->nChannels; i++) {
          sprintf(sp, "%d", i + 1);
          if (jack_connect(p->client, jack_port_name(p->outPorts[i]), dev_final) != 0) {
            rtJack_Error(csound, -1, Str("error connecting output ports"));
          }
        }
        *sp = (char) 0;
      }
    }
{'fraction_non_alphanumeric': 0.14843246725359674, 'fraction_numerical': 0.011702812969722998, 'mean_word_length': 2.3722845763939175, 'pattern_counts': {'":': 0, '<': 59, '<?xml version=': 0, '>': 337, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 64, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3339694', 'n_tokens_mistral': 13103, 'n_tokens_neox': 12685, 'n_words': 3047}