Guest User

Untitled

a guest
May 12th, 2013
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 11.32 KB | None | 0 0
  1. /*  Rhodon Tracker - All-In-One Music studio
  2.  *  Copyright (C) 2013 Henrik Andersson <[email protected]>
  3.  *
  4.  *  This program is free software: you can redistribute it and/or modify
  5.  *  it under the terms of the GNU General Public License as published by
  6.  *  the Free Software Foundation, either version 3 of the License, or
  7.  *  (at your option) any later version.
  8.  *
  9.  *  This program is distributed in the hope that it will be useful,
  10.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *  GNU General Public License for more details.
  13.  *
  14.  *  You should have received a copy of the GNU General Public License
  15.  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16.  */
  17.  
  18. #include "instruments/csound_instrument.h"
  19. #include <csound/csound.h>
  20. #include <string.h>
  21.  
  22. #define RT_CSOUND_INSTRUMENT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), RT_TYPE_CSOUND_INSTRUMENT, RTCsoundInstrumentPrivate))
  23.  
  24. typedef struct _controller_def_t
  25. {
  26.   float default_value;
  27.   float min_value;
  28.   float max_value;
  29. } _controller_def_t;
  30.  
  31. struct _RTCsoundInstrumentPrivate
  32. {
  33.   CSOUND *csound;
  34.   gboolean loaded;
  35.  
  36.   MYFLT *aout;
  37.   int aout_channels;
  38.  
  39.   guint control_cnt;
  40.   gchar **control_names;
  41.   MYFLT *control_ports;
  42.   _controller_def_t *control_def;
  43.  
  44.   GQueue *midi_events;
  45.  
  46. };
  47.  
  48. G_DEFINE_TYPE(RTCsoundInstrument, rt_csound_instrument, RT_TYPE_INSTRUMENT)
  49.  
  50. static int
  51. _csound_instrument_midi_device_open_cb(CSOUND *csound, void **userdata, const char *devname)
  52. {
  53.   g_message("Csound Instrument: Midi device open callback");
  54.   *userdata = csoundGetHostData(csound);
  55.   return 0;
  56. }
  57.  
  58. static int
  59. _csound_instrument_midi_read_cb(CSOUND *csound, void *userdata, unsigned char *buf, int bytes)
  60. {
  61.   gint cnt;
  62.   guint32 midi;
  63.   RTCsoundInstrument *self;
  64.  
  65.   g_assert(userdata != NULL);
  66.  
  67.   self = RT_CSOUND_INSTRUMENT(userdata);
  68.  
  69.   cnt = 0;
  70.   while(!g_queue_is_empty(self->priv->midi_events) && cnt <= (bytes-3))
  71.   {
  72.     midi = GPOINTER_TO_UINT(g_queue_peek_head(self->priv->midi_events));
  73.  
  74.     buf[cnt+0] = (unsigned char) ((midi & 0xff0000) >> 16);
  75.     buf[cnt+1] = (unsigned char) ((midi & 0xff00) >> 8);
  76.     buf[cnt+2] = (unsigned char) (midi & 0xff);
  77.  
  78.     g_message("Csound Instrument: Midi event %.2x%.2x%.2x",
  79.           buf[cnt], buf[cnt+1], buf[cnt+2]);
  80.     g_queue_pop_head(self->priv->midi_events);
  81.  
  82.     switch (buf[cnt] & 0xF0) {
  83.     case 0x80:    /* note off */
  84.     case 0x90:    /* note on */
  85.     case 0xA0:    /* polyphonic pressure */
  86.     case 0xB0:    /* control change */
  87.     case 0xE0:    /* pitch bend */
  88.       cnt += 3;
  89.       break;
  90.     case 0xC0:    /* program change */
  91.     case 0xD0:    /* channel pressure */
  92.       cnt += 2;
  93.       break;
  94.     case 0xF0:
  95.       switch (buf[cnt]) {
  96.       case 0xF8:    /* timing clock */
  97.       case 0xFA:    /* start */
  98.       case 0xFB:    /* continue */
  99.       case 0xFC:    /* stop */
  100.       case 0xFF:    /* reset */
  101.         cnt++;
  102.       }
  103.       break;      /* ignore any other message */
  104.     }
  105.   }
  106.  
  107.   return cnt;
  108. }
  109.  
  110.  
  111. static const gchar *
  112. _csound_instrument_program_name(RTMachine *machine, guint index)
  113. {
  114.   return NULL;
  115. }
  116.  
  117. static void
  118. _csound_instrument_program_set(RTMachine *machine, guint index)
  119. {
  120. }
  121.  
  122. static void
  123. _csound_instrument_note_on(RTInstrument *self, guint8 note, guint8 velocity)
  124. {
  125.   RTCsoundInstrument *synth;
  126.   guint8 channel;
  127.   guint32 midi;
  128.  
  129.   synth = RT_CSOUND_INSTRUMENT(self);
  130.  
  131.   channel = 0;
  132.  
  133.   midi = (0x90 | channel) << 16  | (note) << 8 | velocity;
  134.  
  135.   g_queue_push_tail(synth->priv->midi_events,
  136.             GUINT_TO_POINTER(midi));
  137.  
  138. }
  139.  
  140. static void
  141. _csound_instrument_note_off(RTInstrument *self, guint8 note)
  142. {
  143.   RTCsoundInstrument *synth;
  144.   guint8 channel;
  145.   guint32 midi;
  146.  
  147.   synth = RT_CSOUND_INSTRUMENT(self);
  148.  
  149.   channel = 0;
  150.  
  151.   midi = (0x80 | channel) << 16  | (note) << 8 | 0;
  152.  
  153.   g_queue_push_tail(synth->priv->midi_events,
  154.             GUINT_TO_POINTER(midi));
  155. }
  156.  
  157. static const gchar *
  158. _csound_instrument_controller_name(RTMachine *machine, guint index)
  159. {
  160.   RTCsoundInstrument *self;
  161.  
  162.   self = RT_CSOUND_INSTRUMENT(machine);
  163.  
  164.   if (index >= self->priv->control_cnt)
  165.     return NULL;
  166.  
  167.   return self->priv->control_names[index];
  168. }
  169.  
  170. static void
  171. _csound_instrument_controller_get_range(RTMachine *machine, guint index,
  172.                     float *min, float *max)
  173. {
  174.   RTCsoundInstrument *self;
  175.  
  176.   self = RT_CSOUND_INSTRUMENT(machine);
  177.  
  178.   if (index >= self->priv->control_cnt)
  179.     return;
  180.  
  181.   /* sanity checking */
  182.   if (self->priv->control_def[index].min_value >=
  183.       self->priv->control_def[index].max_value)
  184.     return;
  185.  
  186.   *min = self->priv->control_def[index].min_value;
  187.   *max = self->priv->control_def[index].max_value;
  188. }
  189.  
  190. static float
  191. _csound_instrument_controller_get_default(RTMachine *machine, guint index)
  192. {
  193.   RTCsoundInstrument *self;
  194.  
  195.   self = RT_CSOUND_INSTRUMENT(machine);
  196.  
  197.   if (index >= self->priv->control_cnt)
  198.     return 1.0;
  199.  
  200.   return  self->priv->control_def[index].default_value;
  201. }
  202.  
  203. static float
  204. _csound_instrument_controller_get_value(RTMachine *machine, guint index)
  205. {
  206.   RTCsoundInstrument *self;
  207.   int err;
  208.  
  209.   self = RT_CSOUND_INSTRUMENT(machine);
  210.  
  211.   if (index >= self->priv->control_cnt)
  212.     return NAN;
  213.  
  214.   return csoundGetControlChannel(self->priv->csound,
  215.                  self->priv->control_names[index],
  216.                  &err);
  217. }
  218.  
  219. static void
  220. _csound_instrument_controller_set_value(RTMachine *machine, guint index, float value)
  221. {
  222.   RTCsoundInstrument *self;
  223.  
  224.   self = RT_CSOUND_INSTRUMENT(machine);
  225.  
  226.   if (index >= self->priv->control_cnt)
  227.     return;
  228.  
  229.   csoundSetControlChannel(self->priv->csound,
  230.               self->priv->control_names[index],
  231.               self->priv->control_ports[index]);
  232. }
  233.  
  234. static void
  235. _csound_instrument_process(RTMachine *self, float *left, float *right, size_t want_frames)
  236. {
  237.   RTCsoundInstrument *csound;
  238.   static guint iframes = 0;
  239.   guint i, ksmps;
  240.   MYFLT scale;
  241.  
  242.   csound = RT_CSOUND_INSTRUMENT(self);
  243.  
  244.   ksmps = csoundGetKsmps(csound->priv->csound);
  245.   scale = csoundGet0dBFS(csound->priv->csound);
  246.  
  247. #if 0
  248.   /* update controllers */
  249.   for (i = 0; i < csound->priv->control_cnt; i++)
  250.     csoundSetControlChannel(csound->priv->csound,
  251.                 csound->priv->control_names[i],
  252.                 csound->priv->control_ports[i]);
  253. #endif
  254.  
  255.   /* process samples */
  256.   for (i = 0; i < want_frames; i++, iframes++)
  257.   {
  258.     if (iframes == ksmps)
  259.     {
  260.       csoundPerformKsmps(csound->priv->csound);
  261.       iframes = 0;
  262.     }
  263.     right[i] = left[i] = (csound->priv->aout[iframes] / scale);
  264.   }
  265.  
  266. }
  267.  
  268. static void
  269. _csound_dispose(GObject *obj)
  270. {
  271.   G_OBJECT_CLASS(rt_csound_instrument_parent_class)->dispose(obj);
  272. }
  273.  
  274. static void
  275. _csound_finalize(GObject *obj)
  276. {
  277.   RTCsoundInstrument *self;
  278.  
  279.   self = RT_CSOUND_INSTRUMENT(obj);
  280.  
  281.   /* destroy csound */
  282.   csoundCleanup(self->priv->csound);
  283.   csoundDestroy(self->priv->csound);
  284.  
  285.   G_OBJECT_CLASS(rt_csound_instrument_parent_class)->finalize(obj);
  286. }
  287.  
  288. static void
  289. rt_csound_instrument_class_init(RTCsoundInstrumentClass *klass)
  290. {
  291.   GObjectClass *class;
  292.   RTInstrumentClass *ic;
  293.   RTMachineClass *mc;
  294.   g_type_class_add_private(klass, sizeof(RTCsoundInstrumentPrivate));
  295.  
  296.   class = G_OBJECT_CLASS(klass);
  297.   class->dispose = _csound_dispose;
  298.   class->finalize = _csound_finalize;
  299.  
  300.   /* Instrument virtual funcitons */
  301.   ic = RT_INSTRUMENT_CLASS(klass);
  302.   ic->note_on = _csound_instrument_note_on;
  303.   ic->note_off = _csound_instrument_note_off;
  304.  
  305.   /* Machine virtual functions */
  306.   mc = RT_MACHINE_CLASS(klass);
  307.   mc->process = _csound_instrument_process;
  308.   mc->controller_name = _csound_instrument_controller_name;
  309.   mc->controller_set_value = _csound_instrument_controller_set_value;
  310.   mc->controller_get_value = _csound_instrument_controller_get_value;
  311.   mc->controller_get_default = _csound_instrument_controller_get_default;
  312.   mc->controller_get_range = _csound_instrument_controller_get_range;
  313.  
  314.   mc->program_name = _csound_instrument_program_name;
  315.   mc->program_set = _csound_instrument_program_set;
  316. }
  317.  
  318. static void
  319. rt_csound_instrument_init(RTCsoundInstrument *self)
  320. {
  321.   self->priv = RT_CSOUND_INSTRUMENT_GET_PRIVATE(self);
  322.  
  323.   g_object_set(self,
  324.            "name", "Csound",
  325.            NULL);
  326.  
  327.   self->priv->midi_events = g_queue_new();
  328.   g_queue_clear(self->priv->midi_events);
  329.  
  330.  
  331.   self->priv->csound = csoundCreate(self);
  332. }
  333.  
  334. gboolean
  335. rt_csound_instrument_load(RTCsoundInstrument *self, const gchar *filename)
  336. {
  337.   volatile guint i;
  338.   gint res;
  339.   gint argc;
  340.   char **argv;
  341.   controlChannelInfo_t *clst;
  342.   controlChannelHints_t hints;
  343.   guint ci = 0;
  344.  
  345.   /* compile csound instrument */
  346.   argc = 3;
  347.   argv = g_malloc(sizeof(char *) * argc);
  348.   argv[0] = "csound";
  349.   argv[1] = filename;
  350.   argv[2] = "-+rtmidi=null";
  351.  
  352.   /* setup csound audio output */
  353.   csoundSetOption(self->priv->csound, "--nosound");
  354.   csoundSetOption(self->priv->csound, "--sample-rate=44100");
  355.   csoundSetOption(self->priv->csound, "--control-rate=4410");
  356.  
  357.   csoundSetOutput(self->priv->csound, "dac", NULL, NULL);
  358.   csoundSetRTAudioModule(self->priv->csound, "null");
  359.   csoundSetHostImplementedAudioIO(self->priv->csound, 1, 0);
  360.  
  361.   /* setup csound midi input requires rtmidi=null */
  362.   csoundSetExternalMidiInOpenCallback(self->priv->csound,
  363.                       _csound_instrument_midi_device_open_cb);
  364.   csoundSetExternalMidiReadCallback(self->priv->csound,
  365.                     _csound_instrument_midi_read_cb);
  366.  
  367.   /* compile program */
  368.   res = csoundCompile(self->priv->csound, argc, argv);
  369.   if (res != CSOUND_SUCCESS)
  370.   {
  371.     g_warning("Csound Instrument: Failed to compile '%s'", filename);
  372.     return FALSE;
  373.   }
  374.  
  375.   /* turn of score events, only use live performance */
  376.   csoundSetScorePending(self->priv->csound, 1);
  377.  
  378.   /* get the number of output channels */
  379.   self->priv->aout_channels = csoundGetNchnls(self->priv->csound);
  380.   self->priv->aout = csoundGetSpout(self->priv->csound);
  381.  
  382.   /* get the channel list */
  383.   res = csoundListChannels(self->priv->csound, &clst);
  384.   if (res == 0)
  385.   {
  386.     g_warning("CSound Instrument: No channels defined.");
  387.     return FALSE;
  388.   }
  389.  
  390.   if (res == CSOUND_MEMORY)
  391.   {
  392.     g_warning("CSound Instrument: No memory left for channel list.");
  393.     return FALSE;
  394.   }
  395.  
  396.   /* parse control channels */
  397.   ci = 0;
  398.   self->priv->control_cnt = 0;
  399.   self->priv->control_names = g_malloc(sizeof(gchar *) * res);
  400.   self->priv->control_ports = g_malloc(sizeof(MYFLT) * res);
  401.   self->priv->control_def = g_malloc(sizeof(_controller_def_t) * res);
  402.  
  403.   memset(self->priv->control_names, 0, sizeof(gchar *) * res);
  404.   memset(self->priv->control_ports, 0, sizeof(MYFLT) * res);
  405.   memset(self->priv->control_def, 0, sizeof(_controller_def_t) * res);
  406.  
  407.   memset(&hints, 0, sizeof(controlChannelHints_t));
  408.  
  409.   for (i = 0; i < res; i++)
  410.   {
  411.     if ((clst[i].type & CSOUND_CONTROL_CHANNEL) == CSOUND_CONTROL_CHANNEL)
  412.     {
  413.       self->priv->control_cnt++;
  414.  
  415.       self->priv->control_names[ci] = g_strdup(clst[i].name);
  416.  
  417.       if (!(clst[i].hints.behav & CSOUND_CONTROL_CHANNEL_NO_HINTS))
  418.       {
  419.     self->priv->control_def[i].default_value = clst[i].hints.dflt;
  420.     self->priv->control_def[i].min_value = clst[i].hints.min;
  421.     self->priv->control_def[i].max_value = clst[i].hints.max;
  422.       }
  423.  
  424.       ci++;
  425.     }
  426.   }
  427.  
  428.   csoundDeleteChannelList(self->priv->csound, clst);
  429.  
  430.   g_object_set(self, "name", filename, NULL);
  431.  
  432.   return TRUE;
  433. }
Advertisement
Add Comment
Please, Sign In to add comment