<commit_before>/*
    pmidi.c:

    Copyright (C) 2004 <NAME> after <NAME>
              (C) 2005 <NAME>
              (C) 2008 <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
*/

/* Realtime MIDI using Portmidi library */

#include "csdl.h"                               /*      PMIDI.C         */
#include "csGblMtx.h"
#include "midiops.h"
#include <portmidi.h>
#include <porttime.h>

/* Stub for compiling this file with MinGW and linking
   with portmidi.lib built witn MSVC AND with Windows
   libraries from MinGW (missing __wassert).
*/
#if defined(WIN32) && !defined(MSVC)

void _wassert(wchar_t *condition)
{
}

#endif

typedef struct _pmall_data {
  PortMidiStream *midistream;
  struct _pmall_data *next;
} pmall_data;

static  const   int     datbyts[8] = { 2, 2, 2, 2, 1, 1, 2, 0 };

static int portMidiErrMsg(CSOUND *csound, const char *msg, ...)
{
    va_list args;

    va_start(args, msg);
    csound->ErrMsgV(csound, " *** PortMIDI: ", msg, args);
    va_end(args);
    return -1;
}

static int portMidi_getDeviceCount(int output)
{
    int           i, cnt1, cnt2;
    PmDeviceInfo  *info;

    cnt1 = (int)Pm_CountDevices();
    if (UNLIKELY(cnt1 < 1))
      return cnt1;      /* no devices */
    cnt2 = 0;
    for (i = 0; i < cnt1; i++) {
      info = (PmDeviceInfo*)Pm_GetDeviceInfo((PmDeviceID) i);
      if (output && info->output)
        cnt2++;
      else if (!output && info->input)
        cnt2++;
    }
    return cnt2;
}

static int portMidi_getRealDeviceID(int dev, int output)
{
    int           i, j, cnt;
    PmDeviceInfo  *info;

    cnt = (int)Pm_CountDevices();
    i = j = -1;
    while (++i < cnt) {
      info = (PmDeviceInfo*)Pm_GetDeviceInfo((PmDeviceID) i);
      if ((output && !(info->output)) || (!output && !(info->input)))
        continue;
      if (++j == dev)
        return i;
    }
    return -1;
}

static int portMidi_getPackedDeviceID(int dev, int output)
{
    int           i, j, cnt;
    PmDeviceInfo  *info;

    cnt = (int)Pm_CountDevices();
    i = j = -1;
    while (++i < cnt) {
      info = (PmDeviceInfo*)Pm_GetDeviceInfo((PmDeviceID) i);
      if ((output && info->output) || (!output && info->input))
        j++;
      if (i == dev)
        return j;
    }
    return -1;
}

static PmDeviceInfo *portMidi_getDeviceInfo(int dev, int output)
{
    int i;

    i = portMidi_getRealDeviceID(dev, output);
    if (UNLIKELY(i < 0))
      return NULL;
    return ((PmDeviceInfo*)Pm_GetDeviceInfo((PmDeviceID) i));
}
/* reference count for PortMidi initialisation */

static unsigned long portmidi_init_cnt = 0UL;

static int stop_portmidi(CSOUND *csound, void *userData)
{
    (void) csound;
    (void) userData;
    csound_global_mutex_lock();
    if (portmidi_init_cnt) {
      if (--portmidi_init_cnt == 0UL) {
        Pm_Terminate();
        Pt_Stop();
      }
    }
    csound_global_mutex_unlock();
    return 0;
}

static int start_portmidi(CSOUND *csound)
{
    const char  *errMsg = NULL;

    csound_global_mutex_lock();
    if (!portmidi_init_cnt) {
      if (UNLIKELY(Pm_Initialize() != pmNoError))
        errMsg = Str(" *** error initialising PortMIDI");
      else if (UNLIKELY(Pt_Start(1, NULL, NULL) != ptNoError))
        errMsg = Str(" *** error initialising PortTime");
      }

    if (errMsg == NULL)
      portmidi_init_cnt++;
    csound_global_mutex_unlock();
    if (UNLIKELY(errMsg != NULL)) {
      csound->ErrorMsg(csound, Str(errMsg));
      return -1;
    }
    csound_global_mutex_unlock();
    return csound->RegisterResetCallback(csound, NULL, stop_portmidi);
}

static int listDevices(CSOUND *csound, CS_MIDIDEVICE *list, int isOutput){
  int i, cnt;
  PmDeviceInfo  *info;
  char tmp[64];
  char *drv = (char*) (csound->QueryGlobalVariable(csound, "_RTMIDI"));

  if (UNLIKELY(start_portmidi(csound) != 0))
      return 0;

  cnt = portMidi_getDeviceCount(isOutput);
  if(list == NULL) return cnt;
  for (i = 0; i < cnt; i++) {
      info = portMidi_getDeviceInfo(i, isOutput);
      strncpy(list[i].device_name, info->name, 63);
      snprintf(tmp, 64, "%d", i);
      strncpy(list[i].device_id, tmp, 63);
      list[i].isOutput = isOutput;
      if (info->interf != NULL)
         strncpy(list[i].interface_name, info->interf, 63);
      else strcpy(list[i].interface_name, "");
     strncpy(list[i].midi_module, drv, 63);
  }
  return cnt;
}

static void portMidi_listDevices(CSOUND *csound, int output)
{
    int i,n = listDevices(csound, NULL, output);
    CS_MIDIDEVICE *devs =
      (CS_MIDIDEVICE *) csound->Malloc(csound, n*sizeof(CS_MIDIDEVICE));<commit_msg>fix double unlock in pmidi<commit_after>/*
    pmidi.c:

    Copyright (C) 2004 <NAME> after <NAME>
              (C) 2005 <NAME>
              (C) 2008 <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
*/

/* Realtime MIDI using Portmidi library */

#include "csdl.h"                               /*      PMIDI.C         */
#include "csGblMtx.h"
#include "midiops.h"
#include <portmidi.h>
#include <porttime.h>

/* Stub for compiling this file with MinGW and linking
   with portmidi.lib built witn MSVC AND with Windows
   libraries from MinGW (missing __wassert).
*/
#if defined(WIN32) && !defined(MSVC)

void _wassert(wchar_t *condition)
{
}

#endif

typedef struct _pmall_data {
  PortMidiStream *midistream;
  struct _pmall_data *next;
} pmall_data;

static  const   int     datbyts[8] = { 2, 2, 2, 2, 1, 1, 2, 0 };

static int portMidiErrMsg(CSOUND *csound, const char *msg, ...)
{
    va_list args;

    va_start(args, msg);
    csound->ErrMsgV(csound, " *** PortMIDI: ", msg, args);
    va_end(args);
    return -1;
}

static int portMidi_getDeviceCount(int output)
{
    int           i, cnt1, cnt2;
    PmDeviceInfo  *info;

    cnt1 = (int)Pm_CountDevices();
    if (UNLIKELY(cnt1 < 1))
      return cnt1;      /* no devices */
    cnt2 = 0;
    for (i = 0; i < cnt1; i++) {
      info = (PmDeviceInfo*)Pm_GetDeviceInfo((PmDeviceID) i);
      if (output && info->output)
        cnt2++;
      else if (!output && info->input)
        cnt2++;
    }
    return cnt2;
}

static int portMidi_getRealDeviceID(int dev, int output)
{
    int           i, j, cnt;
    PmDeviceInfo  *info;

    cnt = (int)Pm_CountDevices();
    i = j = -1;
    while (++i < cnt) {
      info = (PmDeviceInfo*)Pm_GetDeviceInfo((PmDeviceID) i);
      if ((output && !(info->output)) || (!output && !(info->input)))
        continue;
      if (++j == dev)
        return i;
    }
    return -1;
}

static int portMidi_getPackedDeviceID(int dev, int output)
{
    int           i, j, cnt;
    PmDeviceInfo  *info;

    cnt = (int)Pm_CountDevices();
    i = j = -1;
    while (++i < cnt) {
      info = (PmDeviceInfo*)Pm_GetDeviceInfo((PmDeviceID) i);
      if ((output && info->output) || (!output && info->input))
        j++;
      if (i == dev)
        return j;
    }
    return -1;
}

static PmDeviceInfo *portMidi_getDeviceInfo(int dev, int output)
{
    int i;

    i = portMidi_getRealDeviceID(dev, output);
    if (UNLIKELY(i < 0))
      return NULL;
    return ((PmDeviceInfo*)Pm_GetDeviceInfo((PmDeviceID) i));
}
/* reference count for PortMidi initialisation */

static unsigned long portmidi_init_cnt = 0UL;

static int stop_portmidi(CSOUND *csound, void *userData)
{
    (void) csound;
    (void) userData;
    csound_global_mutex_lock();
    if (portmidi_init_cnt) {
      if (--portmidi_init_cnt == 0UL) {
        Pm_Terminate();
        Pt_Stop();
      }
    }
    csound_global_mutex_unlock();
    return 0;
}

static int start_portmidi(CSOUND *csound)
{
    const char  *errMsg = NULL;

    csound_global_mutex_lock();
    if (!portmidi_init_cnt) {
      if (UNLIKELY(Pm_Initialize() != pmNoError))
        errMsg = Str(" *** error initialising PortMIDI");
      else if (UNLIKELY(Pt_Start(1, NULL, NULL) != ptNoError))
        errMsg = Str(" *** error initialising PortTime");
      }

    if (errMsg == NULL)
      portmidi_init_cnt++;
    csound_global_mutex_unlock();
    if (UNLIKELY(errMsg != NULL)) {
      csound->ErrorMsg(csound, Str(errMsg));
      return -1;
    }
    //csound_global_mutex_unlock();
    return csound->RegisterResetCallback(csound, NULL, stop_portmidi);
}

static int listDevices(CSOUND *csound, CS_MIDIDEVICE *list, int isOutput){
  int i, cnt;
  PmDeviceInfo  *info;
  char tmp[64];
  char *drv = (char*) (csound->QueryGlobalVariable(csound, "_RTMIDI"));

  if (UNLIKELY(start_portmidi(csound) != 0))
      return 0;

  cnt = portMidi_getDeviceCount(isOutput);
  if (list == NULL) return cnt;
  for (i = 0; i < cnt; i++) {
      info = portMidi_getDeviceInfo(i, isOutput);
      strncpy(list[i].device_name, info->name, 63);
      snprintf(tmp, 64, "%d", i);
      strncpy(list[i].device_id, tmp, 63);
      list[i].isOutput = isOutput;
      if (info->interf != NULL)
         strncpy(list[i].interface_name, info->interf, 63);
      else strcpy(list[i].interface_name, "");
     strncpy(list[i].midi_module, drv, 63);
  }
  return cnt;
}

static void portMidi_listDevices(CSOUND *csound, int output)
{
    int i,n = listDevices(csound, NULL, output);
    CS_MIDIDEVICE *devs =
      (CS_MIDIDEVICE *) csound->Malloc(csound, n*sizeof(CS_MIDIDEVICE));
{'fraction_non_alphanumeric': 0.12563571294029008, 'fraction_numerical': 0.014692032397815032, 'mean_word_length': 2.8530478955007257, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7338904', 'n_tokens_mistral': 3892, 'n_tokens_neox': 3751, 'n_words': 1024}