M astrid/orc/littlefield.c => astrid/orc/littlefield.c +31 -24
@@ 7,7 7,7 @@
#define ADC_LENGTH 30
#define MIC_ATTENUATION 0.2f
-#define NUMOSCS 20
+#define NUMOSCS 10
#define WTSIZE 4096
#define MAXNUMFREQS NUMOSCS
@@ 176,6 176,13 @@ int param_map_callback(void * arg, char * keystr, char * valstr) {
} else if(strcmp(keystr, "freqs") == 0) {
num_freqs = extract_floatlist_from_token(valstr, val_floatlist, MAXNUMFREQS);
astrid_instrument_set_param_float_list(instrument, PARAM_OSC_FREQS, val_floatlist, num_freqs);
+ } else if(strcmp(keystr, "oo1") == 0) {
+ extract_float_from_token(valstr, &val_f);
+ astrid_instrument_set_param_float(instrument, PARAM_OSC_TO_OUT1, val_f);
+ } else if(strcmp(keystr, "oo2") == 0) {
+ extract_float_from_token(valstr, &val_f);
+ astrid_instrument_set_param_float(instrument, PARAM_OSC_TO_OUT2, val_f);
+
} else if(strcmp(keystr, "gamp") == 0) {
extract_float_from_token(valstr, &val_f);
@@ 208,7 215,14 @@ int param_map_callback(void * arg, char * keystr, char * valstr) {
extract_float_from_token(valstr, &val_f);
astrid_instrument_set_param_float(instrument, PARAM_GATE_DRIFT_PERIODICITY, val_f);
- } else if(strcmp(keystr, "gpat") == 0) {
+ } else if(strcmp(keystr, "go1") == 0) {
+ extract_float_from_token(valstr, &val_f);
+ astrid_instrument_set_param_float(instrument, PARAM_GATE_TO_OUT1, val_f);
+ } else if(strcmp(keystr, "go2") == 0) {
+ extract_float_from_token(valstr, &val_f);
+ astrid_instrument_set_param_float(instrument, PARAM_GATE_TO_OUT2, val_f);
+
+ } else if(strcmp(keystr, "pat") == 0) {
extract_patternbuf_from_token(valstr, val_pattern.pattern, &val_pattern.length);
astrid_instrument_set_param_patternbuf(instrument, PARAM_GATE_PATTERN, &val_pattern);
} else if(strcmp(keystr, "greset") == 0) {
@@ 230,20 244,6 @@ int param_map_callback(void * arg, char * keystr, char * valstr) {
extract_float_from_token(valstr, &val_f);
astrid_instrument_set_param_float(instrument, PARAM_IN2_TO_OUT2, val_f);
- } else if(strcmp(keystr, "oo1") == 0) {
- extract_float_from_token(valstr, &val_f);
- astrid_instrument_set_param_float(instrument, PARAM_OSC_TO_OUT1, val_f);
- } else if(strcmp(keystr, "oo2") == 0) {
- extract_float_from_token(valstr, &val_f);
- astrid_instrument_set_param_float(instrument, PARAM_OSC_TO_OUT2, val_f);
-
- } else if(strcmp(keystr, "go1") == 0) {
- extract_float_from_token(valstr, &val_f);
- astrid_instrument_set_param_float(instrument, PARAM_GATE_TO_OUT1, val_f);
- } else if(strcmp(keystr, "go2") == 0) {
- extract_float_from_token(valstr, &val_f);
- astrid_instrument_set_param_float(instrument, PARAM_GATE_TO_OUT2, val_f);
-
} else if(strcmp(keystr, "disttype") == 0) {
extract_int32_from_token(valstr, &val_i32);
if(val_i32 < 0 || val_i32 >= NUM_DISTORTIONS) val_i32 = DISTORTION_FOLDBACK;
@@ 258,6 258,13 @@ int param_map_callback(void * arg, char * keystr, char * valstr) {
} else if(strcmp(keystr, "mtrak") == 0) {
extract_int32_from_token(valstr, &val_i32);
astrid_instrument_set_param_int32(instrument, PARAM_MIC_PITCH_TRACKING_ENABLED, val_i32);
+
+ } else if(strcmp(keystr, "save") == 0) {
+ extract_int32_from_token(valstr, &val_i32);
+ astrid_instrument_save_param_session_snapshot(instrument, NUMPARAMS, val_i32);
+ } else if(strcmp(keystr, "restore") == 0) {
+ extract_int32_from_token(valstr, &val_i32);
+ astrid_instrument_restore_param_session_snapshot(instrument, val_i32);
}
return 0;
@@ 307,19 314,19 @@ int audio_callback(size_t blocksize, float ** input, float ** output, void * arg
distortion_mix = astrid_instrument_get_param_float(instrument, PARAM_DISTORTION_MIX, 0.f);
distortion_type = astrid_instrument_get_param_int32(instrument, PARAM_DISTORTION_TYPE, 0);
- osc_amp = astrid_instrument_get_param_float(instrument, PARAM_OSC_AMP, 0.f);
+ osc_amp = astrid_instrument_get_param_float(instrument, PARAM_OSC_AMP, 1.f);
osc_out1_mix = astrid_instrument_get_param_float(instrument, PARAM_OSC_TO_OUT1, 0.5f);
osc_out2_mix = astrid_instrument_get_param_float(instrument, PARAM_OSC_TO_OUT2, 0.5f);
osc_pw = astrid_instrument_get_param_float(instrument, PARAM_OSC_PULSEWIDTH, 1.f);
osc_saturation = astrid_instrument_get_param_float(instrument, PARAM_OSC_SATURATION, 1.f);
- osc_env_speed = astrid_instrument_get_param_float(instrument, PARAM_OSC_ENVELOPE_SPEED, 0.001f) * 1000.f + 1.f;
- osc_drift_amount = astrid_instrument_get_param_float(instrument, PARAM_OSC_DRIFT_DEPTH, 0.f) * 10.f;
+ osc_env_speed = astrid_instrument_get_param_float(instrument, PARAM_OSC_ENVELOPE_SPEED, 0.001f) * 100.f + 1.f;
+ osc_drift_amount = astrid_instrument_get_param_float(instrument, PARAM_OSC_DRIFT_DEPTH, 0.f);
osc_drift_speed = astrid_instrument_get_param_float(instrument, PARAM_OSC_DRIFT_SPEED, 0.5f);
- octave_spread = astrid_instrument_get_param_int32(instrument, PARAM_OSC_OCTAVE_SPREAD, 0);
- octave_offset = astrid_instrument_get_param_int32(instrument, PARAM_OSC_OCTAVE_OFFSET, 0);
+ octave_spread = astrid_instrument_get_param_int32(instrument, PARAM_OSC_OCTAVE_SPREAD, 6);
+ octave_offset = astrid_instrument_get_param_int32(instrument, PARAM_OSC_OCTAVE_OFFSET, -2);
astrid_instrument_get_param_float_list(instrument, PARAM_OSC_FREQS, num_freqs, freqs);
- gate_amp = astrid_instrument_get_param_float(instrument, PARAM_GATE_AMP, 0.5f);
+ gate_amp = astrid_instrument_get_param_float(instrument, PARAM_GATE_AMP, 0.f);
gate_out1_mix = astrid_instrument_get_param_float(instrument, PARAM_GATE_TO_OUT1, 0.5f);
gate_out2_mix = astrid_instrument_get_param_float(instrument, PARAM_GATE_TO_OUT2, 0.5f);
gate_reset = astrid_instrument_get_param_int32(instrument, PARAM_GATE_PHASE_RESET, 0);
@@ 373,7 380,7 @@ int audio_callback(size_t blocksize, float ** input, float ** output, void * arg
last_p = p;
}
- tracked_freq = LPFX.lpf1(tracked_freq, &ctx->freqsmooth, 20.f, SR);
+ tracked_freq = LPFX.lpf1(tracked_freq, &ctx->freqsmooth, 100.f, SR);
// track in a ~melodic range
while(tracked_freq >= 800) tracked_freq *= 0.5f;
@@ 429,7 436,7 @@ int audio_callback(size_t blocksize, float ** input, float ** output, void * arg
output[1][i] += (sample * osc_out2_mix) + (gated_sample * gate_out2_mix) + (in2 * in1_out2_mix) + (in2 * in2_out2_mix);
// apply distortion
- if(distortion_mix > 0 && distortion_amount > 0) {
+ if(distortion_amount > 0) {
switch(distortion_type) {
case DISTORTION_FOLDBACK:
d1 = LPFX.fold(output[0][i] * (distortion_amount+1), &ctx->fold1prev, instrument->samplerate);
M astrid/src/astrid.c => astrid/src/astrid.c +210 -1
@@ 3285,7 3285,7 @@ void * instrument_midi_listener_thread(void * arg) {
return 0;
}
- if((ret = snd_seq_connect_from(seq_handle, port, 20, 0)) < 0) {
+ if((ret = snd_seq_connect_from(seq_handle, port, 24, 0)) < 0) {
syslog(LOG_ERR, "%s midi listener: Could not connect to ALSA port. Error: (%d) %s\n", instrument->name, ret, snd_strerror(ret));
snd_seq_close(seq_handle);
return 0;
@@ 3891,6 3891,215 @@ int astrid_instrument_tick(lpinstrument_t * instrument) {
return 0;
}
+
+int astrid_instrument_save_param_session_snapshot(lpinstrument_t * instrument, int num_params, int snapshot_id) {
+ int shmfd;
+ sem_t * sem;
+ void * shm_base;
+ size_t shm_size = 0;
+ size_t offset = 0;
+ char path[PATH_MAX] = {0};
+
+ // Generate the path for the shared memory and semaphore
+ snprintf(path, PATH_MAX, "%s-%s-%d", ASTRID_SESSION_SNAPSHOT_NAME, instrument->name, snapshot_id);
+
+ // Create and initialize the semaphore
+ if((sem = sem_open(path, O_CREAT, LPIPC_PERMS, 1)) == SEM_FAILED) {
+ syslog(LOG_ERR, "Could not create semaphore. (%s) %s\n", path, strerror(errno));
+ return -1;
+ }
+
+ // Calculate the required size for shared memory
+ for(int i = 0; i < num_params; i++) {
+ MDB_val key, data;
+ key.mv_size = sizeof(int);
+ key.mv_data = &i;
+
+ int rc = mdb_txn_renew(instrument->dbtxn_read);
+ if(rc == 0 && mdb_get(instrument->dbtxn_read, instrument->dbi, &key, &data) == 0) {
+ shm_size += sizeof(int) + sizeof(size_t) + data.mv_size;
+ }
+ mdb_txn_reset(instrument->dbtxn_read);
+ }
+
+ // Create and truncate the shared memory segment
+ if((shmfd = shm_open(path, O_CREAT | O_RDWR, LPIPC_PERMS)) < 0) {
+ syslog(LOG_ERR, "Could not create shared memory segment. (%s) %s\n", path, strerror(errno));
+ sem_close(sem);
+ sem_unlink(path);
+ return -1;
+ }
+
+ if(ftruncate(shmfd, shm_size) < 0) {
+ syslog(LOG_ERR, "Could not truncate shared memory segment to size %ld. (%s) %s\n", shm_size, path, strerror(errno));
+ close(shmfd);
+ sem_close(sem);
+ sem_unlink(path);
+ return -1;
+ }
+
+ if((shm_base = mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0)) == MAP_FAILED) {
+ syslog(LOG_ERR, "Could not mmap shared memory segment. (%s) %s\n", path, strerror(errno));
+ close(shmfd);
+ sem_close(sem);
+ sem_unlink(path);
+ return -1;
+ }
+
+ // Lock the semaphore
+ sem_wait(sem);
+
+ // Write data to shared memory
+ for(int i = 0; i < num_params; i++) {
+ MDB_val key, data;
+ key.mv_size = sizeof(int);
+ key.mv_data = &i;
+
+ int rc = mdb_txn_renew(instrument->dbtxn_read);
+ if (rc == 0 && mdb_get(instrument->dbtxn_read, instrument->dbi, &key, &data) == 0) {
+ memcpy((char *)shm_base + offset, &i, sizeof(int));
+ offset += sizeof(int);
+ size_t data_size = data.mv_size;
+ memcpy((char *)shm_base + offset, &data_size, sizeof(size_t));
+ offset += sizeof(size_t);
+ memcpy((char *)shm_base + offset, data.mv_data, data_size);
+ offset += data_size;
+ }
+ mdb_txn_reset(instrument->dbtxn_read);
+ }
+
+ // Unlock the semaphore
+ sem_post(sem);
+
+ // Clean up
+ close(shmfd);
+ sem_close(sem);
+
+ return 0;
+}
+
+int astrid_instrument_restore_param_session_snapshot(lpinstrument_t * instrument, int snapshot_id) {
+ int shmfd;
+ sem_t * sem;
+ void * shm_base;
+ size_t offset = 0;
+ char path[PATH_MAX] = {0};
+
+ // Generate the path for the shared memory and semaphore
+ snprintf(path, PATH_MAX, "%s-%s-%d", ASTRID_SESSION_SNAPSHOT_NAME, instrument->name, snapshot_id);
+
+ // Open the semaphore
+ if((sem = sem_open(path, 0)) == SEM_FAILED) {
+ syslog(LOG_ERR, "Could not open semaphore. (%s) %s\n", path, strerror(errno));
+ return -1;
+ }
+
+ // Open the shared memory segment
+ if((shmfd = shm_open(path, O_RDWR, LPIPC_PERMS)) < 0) {
+ syslog(LOG_ERR, "Could not open shared memory segment. (%s) %s\n", path, strerror(errno));
+ sem_close(sem);
+ return -1;
+ }
+
+ // Get the size of the shared memory segment
+ struct stat shm_stat;
+ if(fstat(shmfd, &shm_stat) < 0) {
+ syslog(LOG_ERR, "Could not get shared memory segment size. (%s) %s\n", path, strerror(errno));
+ close(shmfd);
+ sem_close(sem);
+ return -1;
+ }
+ size_t shm_size = shm_stat.st_size;
+
+ if((shm_base = mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0)) == MAP_FAILED) {
+ syslog(LOG_ERR, "Could not mmap shared memory segment. (%s) %s\n", path, strerror(errno));
+ close(shmfd);
+ sem_close(sem);
+ return -1;
+ }
+
+ // Lock the semaphore
+ sem_wait(sem);
+
+ // Read data from shared memory
+ while(offset < shm_size) {
+ int param_index;
+ size_t data_size;
+ void *data;
+
+ memcpy(¶m_index, (char *)shm_base + offset, sizeof(int));
+ offset += sizeof(int);
+ memcpy(&data_size, (char *)shm_base + offset, sizeof(size_t));
+ offset += sizeof(size_t);
+
+ data = malloc(data_size);
+ if(!data) {
+ syslog(LOG_ERR, "Failed to allocate memory for parameter data.");
+ sem_post(sem);
+ munmap(shm_base, shm_size);
+ close(shmfd);
+ sem_close(sem);
+ return -1;
+ }
+
+ memcpy(data, (char *)shm_base + offset, data_size);
+ offset += data_size;
+
+ MDB_val key, mdb_data;
+ key.mv_size = sizeof(int);
+ key.mv_data = ¶m_index;
+ mdb_data.mv_size = data_size;
+ mdb_data.mv_data = data;
+
+ int rc = mdb_txn_begin(instrument->dbenv, NULL, 0, &instrument->dbtxn_write);
+ if(rc) {
+ syslog(LOG_ERR, "Failed to begin transaction: (%d) %s", rc, mdb_strerror(rc));
+ free(data);
+ sem_post(sem);
+ munmap(shm_base, shm_size);
+ close(shmfd);
+ sem_close(sem);
+ return -1;
+ }
+
+ rc = mdb_put(instrument->dbtxn_write, instrument->dbi, &key, &mdb_data, 0);
+ if(rc) {
+ syslog(LOG_ERR, "Failed to put parameter data: (%d) %s", rc, mdb_strerror(rc));
+ free(data);
+ mdb_txn_abort(instrument->dbtxn_write);
+ sem_post(sem);
+ munmap(shm_base, shm_size);
+ close(shmfd);
+ sem_close(sem);
+ return -1;
+ }
+
+ rc = mdb_txn_commit(instrument->dbtxn_write);
+ if(rc) {
+ syslog(LOG_ERR, "Failed to commit transaction: (%d) %s", rc, mdb_strerror(rc));
+ free(data);
+ sem_post(sem);
+ munmap(shm_base, shm_size);
+ close(shmfd);
+ sem_close(sem);
+ return -1;
+ }
+
+ free(data);
+ }
+
+ // Unlock the semaphore
+ sem_post(sem);
+
+ // Clean up
+ munmap(shm_base, shm_size);
+ close(shmfd);
+ sem_close(sem);
+
+ return 0;
+}
+
+
int32_t astrid_instrument_get_param_int32(lpinstrument_t * instrument, int param_index, int32_t default_value) {
int rc;
MDB_val key, data;
M astrid/src/astrid.h => astrid/src/astrid.h +5 -0
@@ 57,6 57,8 @@
#define ASTRID_SERIAL_CTLBASE_PATH "/tmp/astrid-serialdevice%d-ctl%d"
+#define ASTRID_SESSION_SNAPSHOT_NAME "/astrid-session-snapshot"
+
#define LPKEY_MAXLENGTH 4096
#define ASTRID_MAX_CMDLINE 4096
@@ 336,6 338,9 @@ void astrid_instrument_set_param_float_list(lpinstrument_t * instrument, int par
void astrid_instrument_get_param_float_list(lpinstrument_t * instrument, int param_index, size_t size, lpfloat_t * list);
lpfloat_t astrid_instrument_get_param_float_list_item(lpinstrument_t * instrument, int param_index, size_t size, int item_index, lpfloat_t default_value);
+int astrid_instrument_restore_param_session_snapshot(lpinstrument_t * instrument, int snapshot_id);
+int astrid_instrument_save_param_session_snapshot(lpinstrument_t * instrument, int num_params, int snapshot_id);
+
int astrid_instrument_tick(lpinstrument_t * instrument);
int astrid_instrument_session_open(lpinstrument_t * instrument);
int astrid_instrument_session_close(lpinstrument_t * instrument);
M pippi/renderer.pyx => pippi/renderer.pyx +6 -0
@@ 477,6 477,12 @@ cdef class Instrument:
cdef EventContext ctx
cdef dict params
cdef str p, k, v
+ cdef size_t last_edit
+
+ last_edit = os.path.getmtime(self.path)
+ if last_edit > self.last_reload:
+ self.reload()
+ self.last_reload = last_edit
if not hasattr(self.renderer, 'update'):
logger.warning('Ignoring update message: this instrument has no callback registered')