M astrid/orc/simple.py => astrid/orc/simple.py +10 -2
@@ 1,8 1,16 @@
-from pippi import dsp, oscs, renderer
+from pippi import dsp, oscs, renderer, fx
+
+def trigger(ctx):
+ return [ctx.t.play(0, 'simple'), ctx.t.trigger(dsp.rand(0.5, 1), 'simple')]
+ #return None
def play(ctx):
ctx.log('Rendering simple tone!')
- yield oscs.SineOsc(freq=dsp.rand(200, 300), amp=1).play(10).env('pluckout')
+ out = oscs.SineOsc(freq=dsp.rand(200, 1000), amp=dsp.rand(0.1, 0.5)).play(10).env('pluckout')
+
+ if dsp.rand() > 0.5:
+ out = fx.fold(out, dsp.rand(1, 2))
+ yield out
if __name__ == '__main__':
renderer.run_forever(__file__)
M astrid/src/astrid.c => astrid/src/astrid.c +31 -20
@@ 2577,6 2577,9 @@ int relay_message_to_seq(lpinstrument_t * instrument) {
seq_delay = instrument->msg.scheduled - (instrument->msg.max_processing_time * 2);
d->timestamp = instrument->msg.initiated + seq_delay;
+ // Remove the scheduled flag before relaying the message
+ d->msg.flags &= ~LPFLAG_IS_SCHEDULED;
+
if(pqueue_insert(instrument->msgpq, (void *)d) < 0) {
syslog(LOG_ERR, "Error while inserting message into pq during msgq loop: %s\n", strerror(errno));
return -1;
@@ 2590,46 2593,53 @@ void * instrument_message_thread(void * arg) {
lpbuffer_t * buf; // async renders: FIXME, do renders in a thread if possible... or fork out early for the python interpreter maybe?
double processing_time_so_far, onset_delay_in_seconds, now=0;
lpinstrument_t * instrument = (lpinstrument_t *)arg;
+ int is_scheduled = 0;
instrument->is_waiting = 1;
while(instrument->is_running) {
- instrument->msg.scheduled = 0;
if(astrid_msgq_read(instrument->msgq, &instrument->msg) == (mqd_t) -1) {
syslog(LOG_ERR, "%s renderer: Could not read message from playq. Error: (%d) %s\n", instrument->name, errno, strerror(errno));
usleep((useconds_t)10000);
return NULL;
}
- syslog(LOG_DEBUG, "MSG: %s\n", instrument->msg.instrument_name);
- syslog(LOG_DEBUG, "MSG: %d (msg.voice_id)\n", (int)instrument->msg.voice_id);
- syslog(LOG_DEBUG, "MSG: %d (msg.type)\n", (int)instrument->msg.type);
-
- // Relay a copy of all messages to python (or in the future maybe other things?)
- // except render complete messages which always get handled here...
- if(instrument->msg.type == LPMSG_RENDER_COMPLETE) {
- if(send_message(instrument->external_relay_name, instrument->msg) < 0) {
- syslog(LOG_ERR, "Could not relay message\n");
- }
- }
+ is_scheduled = ((instrument->msg.flags & LPFLAG_IS_SCHEDULED) == LPFLAG_IS_SCHEDULED);
+ syslog(LOG_DEBUG, "C MSG: name=%s\n", instrument->msg.instrument_name);
+ syslog(LOG_DEBUG, "C MSG: scheduled=%f\n", instrument->msg.scheduled);
+ syslog(LOG_DEBUG, "C MSG: voice_id=%d\n", (int)instrument->msg.voice_id);
+ syslog(LOG_DEBUG, "C MSG: type=%d\n", (int)instrument->msg.type);
+ syslog(LOG_DEBUG, "C MSG: flags=%d\n", (int)instrument->msg.flags);
+ syslog(LOG_DEBUG, "C MSG: is_scheduled=%d\n", is_scheduled);
// Handle shutdown early
if(instrument->msg.type == LPMSG_SHUTDOWN) {
- syslog(LOG_DEBUG, "MSG: shutdown\n");
+ syslog(LOG_DEBUG, "C MSG: shutdown\n");
instrument->is_running = 0;
- // send the shutdown message to the seq thread too
+ // send the shutdown message to the seq thread and external relay
if(relay_message_to_seq(instrument) < 0) {
syslog(LOG_ERR, "%s renderer: Could not read relay message to seq. Error: (%d) %s\n", instrument->name, errno, strerror(errno));
}
+ if(send_message(instrument->external_relay_name, instrument->msg) < 0) {
+ syslog(LOG_ERR, "Could not relay message\n");
+ }
+
break;
}
- // Scheduled messages get sent to the sequencer for handling
- if(instrument->msg.scheduled > 0) {
+ if(is_scheduled) {
+ // Scheduled messages get sent to the sequencer for handling later
+ syslog(LOG_ERR, "C IS SCHEDULED msg.scheduled %f\n", instrument->msg.scheduled);
if(relay_message_to_seq(instrument) < 0) {
syslog(LOG_ERR, "%s renderer: Could not read relay message to seq. Error: (%d) %s\n", instrument->name, errno, strerror(errno));
}
continue;
+ } else {
+ // All other messages get relayed externally, too
+ syslog(LOG_DEBUG, "C MSG: relaying to ext\n");
+ if(send_message(instrument->external_relay_name, instrument->msg) < 0) {
+ syslog(LOG_ERR, "Could not relay message\n");
+ }
}
// Now the fun stuff
@@ 2645,16 2655,17 @@ void * instrument_message_thread(void * arg) {
break;
case LPMSG_UPDATE:
- syslog(LOG_DEBUG, "MSG: update\n");
+ syslog(LOG_DEBUG, "C MSG: update\n");
if(instrument->updates != NULL) instrument->updates(instrument);
break;
case LPMSG_PLAY:
- syslog(LOG_DEBUG, "MSG: play\n");
+ syslog(LOG_DEBUG, "C MSG: play\n");
// Schedule a C callback render if there's a callback defined
// python renders will also be triggered at this point if we're
// inside a python instrument because of the message relay
if(instrument->renderer != NULL) {
+ syslog(LOG_DEBUG, "C MSG: rendering play...\n");
/* FIXME do this in another thread */
buf = instrument->renderer(instrument);
@@ 2687,13 2698,13 @@ void * instrument_message_thread(void * arg) {
case LPMSG_LOAD:
// it would be interesting to explore live reloading of C modules
// in the tradition of CLIVE, but at the moment only python handles these
- syslog(LOG_DEBUG, "MSG: load\n");
+ syslog(LOG_DEBUG, "C MSG: load\n");
break;
case LPMSG_TRIGGER:
// Python only handles these for now, but maybe it would be nice to have optional
// C callbacks here and maybe support raspberry pi GPIO pin toggling / triggers?
- syslog(LOG_DEBUG, "MSG: trigger\n");
+ syslog(LOG_DEBUG, "C MSG: trigger\n");
break;
default:
M libpippi/src/pippiconstants.h => libpippi/src/pippiconstants.h +7 -1
@@ 60,7 60,7 @@
#endif
#define LPMAXNAME 24
-#define LPMAXMSG (PIPE_BUF - (sizeof(double) * 4) - (sizeof(size_t) * 3) - sizeof(uint16_t) - LPMAXNAME)
+#define LPMAXMSG (PIPE_BUF - (sizeof(double) * 4) - (sizeof(size_t) * 3) - (sizeof(uint16_t) * 2) - LPMAXNAME)
enum Wavetables {
@@ 101,6 101,12 @@ enum PanMethods {
NUM_PANMETHODS
};
+enum LPMessageFlags {
+ LPFLAG_NONE,
+ LPFLAG_IS_SCHEDULED,
+ NUM_LPMESSAGEFLAGS
+};
+
enum LPMessageTypes {
LPMSG_EMPTY,
LPMSG_PLAY,
M libpippi/src/pippitypes.h => libpippi/src/pippitypes.h +1 -0
@@ 80,6 80,7 @@ typedef struct lpmsg_t {
size_t voice_id;
size_t count;
+ uint16_t flags;
uint16_t type;
char msg[LPMAXMSG];
char instrument_name[LPMAXNAME];
M pippi/renderer.pxd => pippi/renderer.pxd +6 -0
@@ 54,6 54,11 @@ cdef extern from "astrid.h":
ctypedef struct lpscheduler_t:
pass
+ cdef enum LPMessageFlags:
+ LPFLAG_NONE,
+ LPFLAG_IS_SCHEDULED,
+ NUM_LPMESSAGEFLAGS
+
cdef enum LPMessageTypes:
LPMSG_EMPTY,
LPMSG_PLAY,
@@ 75,6 80,7 @@ cdef extern from "astrid.h":
size_t onset_delay
size_t voice_id
size_t count
+ uint16_t flags
uint16_t type
char msg[LPMAXMSG]
char instrument_name[LPMAXNAME]
M pippi/renderer.pyx => pippi/renderer.pyx +15 -18
@@ 114,6 114,7 @@ cdef class MessageEvent:
self.msg.voice_id = 0
self.msg.count = 0
self.msg.type = msgtype
+ self.msg.flags = LPFLAG_IS_SCHEDULED if onset > 0 else LPFLAG_NONE
strcpy(self.msg.msg, byte_params)
strcpy(self.msg.instrument_name, byte_instrument_name)
@@ 122,7 123,7 @@ cdef class MessageEvent:
self.msg.initiated = now
#logger.debug('CYRENDERER: Sending message type %d to %s' % (self.msg.type, self.msg.instrument_name))
#logger.debug('initiated=%f scheduled=%f voice_id=%d' % (self.msg.initiated, self.msg.scheduled, self.msg.voice_id))
- return send_message(self.msg.instrument_name, self.msg[0])
+ return send_play_message(self.msg[0])
def __dealloc__(self):
if self.msg is not NULL:
@@ 272,14 273,12 @@ cdef class EventTriggerFactory:
return [noteon, noteoff]
def play(self, double onset, str instrument_name, *args, **kwargs):
- global ASTRID_INSTRUMENT
params = self._parse_params(*args, **kwargs)
- return MessageEvent(onset, instrument_name, LPMSG_PLAY, params, ASTRID_INSTRUMENT.max_processing_time)
+ return MessageEvent(onset, instrument_name, LPMSG_PLAY, params, 0)
def trigger(self, double onset, str instrument_name, *args, **kwargs):
- global ASTRID_INSTRUMENT
params = self._parse_params(*args, **kwargs)
- return MessageEvent(onset, instrument_name, LPMSG_TRIGGER, params, ASTRID_INSTRUMENT.max_processing_time)
+ return MessageEvent(onset, instrument_name, LPMSG_TRIGGER, params, 0)
@@ 694,8 693,7 @@ def _wait_on_commands_forever(str instrument_name, stop_event):
def _run_forever(str script_path, str instrument_name, int channels, stop_event):
cdef Instrument instrument = None
cdef lpinstrument_t * i = NULL
- cdef lpmsg_t msg, bufmsg
- cdef lpbuffer_t * buf = NULL
+ cdef lpmsg_t msg
instrument_byte_string = instrument_name.encode('UTF-8')
cdef char * _instrument_ascii_name = instrument_byte_string
@@ 715,25 713,26 @@ def _run_forever(str script_path, str instrument_name, int channels, stop_event)
while True:
logger.info('reading messages...')
- i.msg.scheduled = 0
- if astrid_msgq_read(i.exmsgq, &i.msg) < 0:
+ if astrid_msgq_read(i.exmsgq, &msg) < 0:
print('There was a problem reading from the msg q. Maybe try turning it off and on again?')
continue
- if i.msg.type == LPMSG_SHUTDOWN:
- logger.info('Message loop got shutdown, breaking out!')
+ if msg.type == LPMSG_SHUTDOWN:
+ logger.info('PY MSG: shutdown')
stop_event.set()
break
- elif i.msg.type == LPMSG_PLAY:
- if astrid_schedule_python_render(instrument, &i.msg) < 0:
+ elif msg.type == LPMSG_PLAY:
+ logger.info('PY MSG: play')
+ if astrid_schedule_python_render(instrument, &msg) < 0:
logger.error('Error trying to schedule python render...')
- elif i.msg.type == LPMSG_TRIGGER:
- if astrid_schedule_python_triggers(instrument, &i.msg) < 0:
+ elif msg.type == LPMSG_TRIGGER:
+ logger.info('PY MSG: trigger')
+ if astrid_schedule_python_triggers(instrument, &msg) < 0:
logger.error('Error trying to schedule python triggers...')
- elif i.msg.type == LPMSG_LOAD:
+ elif msg.type == LPMSG_LOAD:
if instrument is None:
instrument = _load_instrument(instrument_name, script_path)
else:
@@ 742,9 741,7 @@ def _run_forever(str script_path, str instrument_name, int channels, stop_event)
instrument.reload()
instrument.last_reload = last_edit
-
logger.info('python instrument shutting down...')
- logger.info('done running forever!?')
def run_forever(str script_path, str instrument_name=None, channels=2):
instrument_name = instrument_name if instrument_name is not None else Path(script_path).stem