Exemple #1
0
static gboolean cbox_instrument_output_process_cmd(struct cbox_instrument *instr, struct cbox_instrument_output *output, struct cbox_command_target *fb, struct cbox_osc_command *cmd, const char *subcmd, GError **error)
{
    if (!strcmp(subcmd, "/status") && !strcmp(cmd->arg_types, ""))
    {
        if (!(cbox_execute_on(fb, NULL, "/gain_linear", "f", error, output->gain) &&
            cbox_execute_on(fb, NULL, "/gain", "f", error, gain2dB_simple(output->gain)) &&
            cbox_execute_on(fb, NULL, "/output", "i", error, output->output_bus + 1)))
            return FALSE;
        return cbox_module_slot_process_cmd(&output->insert, fb, cmd, subcmd, CBOX_GET_DOCUMENT(instr->scene), instr->scene->rt, instr->scene->engine, error);
    }
    if (!strcmp(subcmd, "/gain") && !strcmp(cmd->arg_types, "f"))
    {
        output->gain = dB2gain_simple(CBOX_ARG_F(cmd, 0));
        return TRUE;
    }
    if (!strcmp(subcmd, "/output") && !strcmp(cmd->arg_types, "i"))
    {
        int obus = CBOX_ARG_I(cmd, 0);
        // XXXKF add error checking
        output->output_bus = obus - 1;
        return TRUE;
    }
    if (!strncmp(subcmd, "/rec_dry/", 9))
        return cbox_execute_sub(&output->rec_dry.cmd_target, fb, cmd, subcmd + 8, error);
    if (!strncmp(subcmd, "/rec_wet/", 9))
        return cbox_execute_sub(&output->rec_wet.cmd_target, fb, cmd, subcmd + 8, error);
    return cbox_module_slot_process_cmd(&output->insert, fb, cmd, subcmd, CBOX_GET_DOCUMENT(instr->scene), instr->scene->rt, instr->scene->engine, error);
}
Exemple #2
0
struct cbox_layer *cbox_layer_new(struct cbox_scene *scene)
{
    struct cbox_document *doc = CBOX_GET_DOCUMENT(scene);
    struct cbox_layer *l = malloc(sizeof(struct cbox_layer));
    
    CBOX_OBJECT_HEADER_INIT(l, cbox_layer, doc);
    cbox_command_target_init(&l->cmd_target, cbox_layer_process_cmd, l);
    l->enabled = TRUE;
    l->instrument = NULL;
    l->low_note = 0;
    l->high_note = 127;
    
    l->transpose = 0;
    l->fixed_note = -1;
    l->in_channel = -1;
    l->out_channel = -1;
    l->disable_aftertouch = FALSE;
    l->invert_sustain = FALSE;
    l->consume = FALSE;
    l->ignore_scene_transpose = FALSE;
    l->ignore_program_changes = FALSE;
    l->scene = scene;
    CBOX_OBJECT_REGISTER(l);
    return l;
}
Exemple #3
0
struct cbox_recorder *cbox_recorder_new_stream(struct cbox_engine *engine, struct cbox_rt *rt, const char *filename)
{
    struct stream_recorder *self = malloc(sizeof(struct stream_recorder));
    self->rt = rt;
    self->engine = engine;
    CBOX_OBJECT_HEADER_INIT(&self->iface, cbox_recorder, CBOX_GET_DOCUMENT(engine));
    cbox_command_target_init(&self->iface.cmd_target, stream_recorder_process_cmd, self);
    
    self->iface.user_data = self;
    self->iface.attach = stream_recorder_attach;
    self->iface.record_block = stream_recorder_record_block;
    self->iface.detach = stream_recorder_detach;
    self->iface.destroy = stream_recorder_destroy;
    
    self->sndfile = NULL;
    self->filename = g_strdup(filename);
    self->cur_buffer = NULL;

    self->rb_for_writing = cbox_fifo_new(STREAM_BUFFER_COUNT + 1);
    self->rb_just_written = cbox_fifo_new(STREAM_BUFFER_COUNT + 1);
    sem_init(&self->sem_sync_completed, 0, 0);
    
    CBOX_OBJECT_REGISTER(&self->iface);

    for (uint8_t i = 0; i < STREAM_BUFFER_COUNT; i++)
        cbox_fifo_write_atomic(self->rb_just_written, (char *)&i, 1);
    
    return &self->iface;
}
Exemple #4
0
struct cbox_midi_merger *cbox_engine_get_midi_output(struct cbox_engine *engine, struct cbox_uuid *uuid)
{
    struct cbox_objhdr *objhdr = cbox_document_get_object_by_uuid(CBOX_GET_DOCUMENT(engine), uuid);
    if (!objhdr)
        return NULL;
    struct cbox_scene *scene = (struct cbox_scene *)objhdr;
    if (!CBOX_IS_A(scene, cbox_scene))
        return NULL;
    return &scene->scene_input_merger;
}
Exemple #5
0
struct sampler_layer *sampler_layer_new(struct sampler_module *m, struct sampler_program *parent_program, struct sampler_layer *parent_group)
{
    struct sampler_layer *l = calloc(1, sizeof(struct sampler_layer));
    struct cbox_document *doc = CBOX_GET_DOCUMENT(parent_program);
    memset(l, 0, sizeof(struct sampler_layer));
    CBOX_OBJECT_HEADER_INIT(l, sampler_layer, doc);
    cbox_command_target_init(&l->cmd_target, sampler_layer_process_cmd, l);
    
    l->module = m;
    l->child_layers = g_hash_table_new(NULL, NULL);
    if (parent_group)
    {
        sampler_layer_data_clone(&l->data, &parent_group->data, FALSE);
        l->parent_program = parent_program;
        l->parent_group = parent_group;
        g_hash_table_replace(parent_group->child_layers, l, l);
        l->runtime = NULL;
        CBOX_OBJECT_REGISTER(l);
        return l;
    }
    l->parent_program = parent_program;

    struct sampler_layer_data *ld = &l->data;    
    SAMPLER_FIXED_FIELDS(PROC_FIELDS_INITIALISER)
    
    ld->eff_waveform = NULL;
    ld->eff_freq = 44100;
    ld->velcurve[0] = 0;
    ld->velcurve[127] = 1;
    for (int i = 1; i < 127; i++)
        ld->velcurve[i] = -1;
    ld->modulations = NULL;
    ld->nifs = NULL;
    ld->on_locc = 0;
    ld->on_hicc = 127;
    ld->on_cc_number = -1;

    ld->eff_use_keyswitch = 0;
    l->last_key = -1;
    if (!parent_group)
    {
        sampler_layer_set_modulation1(l, 74, smdest_cutoff, 9600, 2);
        sampler_layer_set_modulation1(l, 71, smdest_resonance, 12, 2);
        sampler_layer_set_modulation(l, smsrc_pitchlfo, 1, smdest_pitch, 100, 0);
    }
    l->runtime = NULL;
    l->unknown_keys = NULL;
    CBOX_OBJECT_REGISTER(l);
    return l;
}
Exemple #6
0
void cbox_song_use_looped_pattern(struct cbox_song *song, struct cbox_midi_pattern *pattern)
{
    assert(pattern->owner == song);
    song->patterns = g_list_remove(song->patterns, pattern);
    pattern->owner = NULL;
    
    cbox_song_clear(song);
    struct cbox_track *trk = cbox_track_new(CBOX_GET_DOCUMENT(song));
    cbox_song_add_track(song, trk);
    cbox_song_add_pattern(song, pattern);
    song->loop_start_ppqn = 0;
    song->loop_end_ppqn = pattern->loop_end;
    cbox_track_add_item(trk, 0, pattern, 0, pattern->loop_end);
    cbox_engine_update_song_playback(app.engine);
}
Exemple #7
0
struct cbox_aux_bus *cbox_aux_bus_load(struct cbox_scene *scene, const char *name, struct cbox_rt *rt, GError **error)
{
    struct cbox_module *module = cbox_module_new_from_fx_preset(name, CBOX_GET_DOCUMENT(scene), rt, scene->engine, error);
    if (!module)
        return NULL;
    
    struct cbox_aux_bus *p = malloc(sizeof(struct cbox_aux_bus));    
    CBOX_OBJECT_HEADER_INIT(p, cbox_aux_bus, CBOX_GET_DOCUMENT(scene));
    cbox_command_target_init(&p->cmd_target, cbox_aux_bus_process_cmd, p);
    p->name = g_strdup(name);
    p->owner = scene;
    p->module = module;
    p->refcount = 0;
    // XXXKF this work up to buffer size of 8192 floats, this should be determined from JACK settings and updated when
    // JACK buffer size changes
    p->input_bufs[0] = malloc(8192 * sizeof(float));
    p->input_bufs[1] = malloc(8192 * sizeof(float));
    p->output_bufs[0] = malloc(8192 * sizeof(float));
    p->output_bufs[1] = malloc(8192 * sizeof(float));
    CBOX_OBJECT_REGISTER(p);
    cbox_scene_insert_aux_bus(scene, p);
    
    return p;
}
Exemple #8
0
static gboolean cbox_instrument_aux_process_cmd(struct cbox_instrument *instr, struct cbox_instrument_output *output, int id, struct cbox_command_target *fb, struct cbox_osc_command *cmd, const char *subcmd, GError **error)
{
    if (!strcmp(subcmd, "/status") && !strcmp(cmd->arg_types, ""))
    {
        if (!cbox_check_fb_channel(fb, cmd->command, error))
            return FALSE;
        if (!(cbox_execute_on(fb, NULL, "/gain_linear", "f", error, output->gain) &&
            cbox_execute_on(fb, NULL, "/gain", "f", error, gain2dB_simple(output->gain)) &&
            cbox_execute_on(fb, NULL, "/bus", "s", error, instr->aux_output_names[id] ? instr->aux_output_names[id] : "")))
            return FALSE;
        return cbox_module_slot_process_cmd(&output->insert, fb, cmd, subcmd, CBOX_GET_DOCUMENT(instr->scene), instr->scene->rt, instr->scene->engine, error);
    }
    else if (!strcmp(subcmd, "/bus") && !strcmp(cmd->arg_types, "s"))
    {
        struct cbox_scene *scene = instr->scene;
        if (!CBOX_ARG_S(cmd, 0))
        {
            struct cbox_aux_bus *old_bus = cbox_rt_swap_pointers(instr->module->rt, (void **)&instr->aux_outputs[id], NULL);
            if (old_bus)
                cbox_aux_bus_unref(old_bus);
            return TRUE;            
        }
        for (int i = 0; i < scene->aux_bus_count; i++)
        {
            if (!scene->aux_buses[i])
                continue;
            if (!strcmp(scene->aux_buses[i]->name, CBOX_ARG_S(cmd, 0)))
            {
                g_free(instr->aux_output_names[id]);
                instr->aux_output_names[id] = g_strdup(scene->aux_buses[i]->name);
                cbox_aux_bus_ref(scene->aux_buses[i]);
                struct cbox_aux_bus *old_bus = cbox_rt_swap_pointers(instr->module->rt, (void **)&instr->aux_outputs[id], scene->aux_buses[i]);
                if (old_bus)
                    cbox_aux_bus_unref(old_bus);
                return TRUE;
            }
        }
        g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Unknown aux bus: %s", CBOX_ARG_S(cmd, 0));
        return FALSE;
    }
    else if (!strcmp(subcmd, "/output") && !strcmp(cmd->arg_types, "i")) // not supported
    {
        cbox_set_command_error(error, cmd);
        return FALSE;
    }
    else // otherwise, treat just like an command on normal (non-aux) output
        return cbox_instrument_output_process_cmd(instr, output, fb, cmd, subcmd, error);
}
Exemple #9
0
static gboolean cbox_aux_bus_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
    struct cbox_aux_bus *aux_bus = ct->user_data;
    struct cbox_rt *rt = (struct cbox_rt *)cbox_document_get_service(CBOX_GET_DOCUMENT(aux_bus), "rt");
    if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
    {
        if (!cbox_check_fb_channel(fb, cmd->command, error))
            return FALSE;

        return cbox_execute_on(fb, NULL, "/name", "s", error, aux_bus->name) && 
            CBOX_OBJECT_DEFAULT_STATUS(aux_bus, fb, error);
    }
    else 
    if (!strncmp(cmd->command, "/slot/", 6))
    {
        return cbox_module_slot_process_cmd(&aux_bus->module, fb, cmd, cmd->command + 5, CBOX_GET_DOCUMENT(aux_bus), rt, aux_bus->owner->engine, error);
    }
    else 
        return cbox_object_default_process_cmd(ct, fb, cmd, error);
}
Exemple #10
0
static gboolean cbox_engine_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
    struct cbox_engine *engine = ct->user_data;
    if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
    {
        for (int i = 0; i < engine->scene_count; i++)
        {
            if (!cbox_execute_on(fb, NULL, "/scene", "o", error, engine->scenes[i]))
                return FALSE;
        }
        return CBOX_OBJECT_DEFAULT_STATUS(engine, fb, error);
    }
    else if (!strcmp(cmd->command, "/render_stereo") && !strcmp(cmd->arg_types, "i"))
    {
        if (!cbox_check_fb_channel(fb, cmd->command, error))
            return FALSE;
        if (engine->rt && engine->rt->io)
        {
            g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot use render function in real-time mode.");
            return FALSE;
        }
        struct cbox_midi_buffer midibuf_song;
        cbox_midi_buffer_init(&midibuf_song);
        int nframes = CBOX_ARG_I(cmd, 0);
        float *data = malloc(2 * nframes * sizeof(float));
        float *data_i = malloc(2 * nframes * sizeof(float));
        float *buffers[2] = { data, data + nframes };
        for (int i = 0; i < nframes; i++)
        {
            buffers[0][i] = 0.f;
            buffers[1][i] = 0.f;
        }
        cbox_engine_process(engine, NULL, nframes, buffers);
        for (int i = 0; i < nframes; i++)
        {
            data_i[i * 2] = buffers[0][i];
            data_i[i * 2 + 1] = buffers[1][i];
        }
        free(data);

        if (!cbox_execute_on(fb, NULL, "/data", "b", error, cbox_blob_new_acquire_data(data_i, nframes * 2 * sizeof(float))))
            return FALSE;
        return TRUE;
    }
    else if (!strncmp(cmd->command, "/master_effect/",15))
    {
        return cbox_module_slot_process_cmd(&engine->effect, fb, cmd, cmd->command + 14, CBOX_GET_DOCUMENT(engine), engine->rt, engine, error);
    }
    else if (!strcmp(cmd->command, "/new_scene") && !strcmp(cmd->arg_types, ""))
    {
        if (!cbox_check_fb_channel(fb, cmd->command, error))
            return FALSE;

        struct cbox_scene *s = cbox_scene_new(CBOX_GET_DOCUMENT(engine), engine);

        return s ? cbox_execute_on(fb, NULL, "/uuid", "o", error, s) : FALSE;
    }
    else if (!strcmp(cmd->command, "/new_recorder") && !strcmp(cmd->arg_types, "s"))
    {
        if (!cbox_check_fb_channel(fb, cmd->command, error))
            return FALSE;

        struct cbox_recorder *rec = cbox_recorder_new_stream(engine, engine->rt, CBOX_ARG_S(cmd, 0));

        return rec ? cbox_execute_on(fb, NULL, "/uuid", "o", error, rec) : FALSE;
    }
    else
        return cbox_object_default_process_cmd(ct, fb, cmd, error);
}
Exemple #11
0
gboolean cbox_song_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
    struct cbox_song *song = ct->user_data;
    if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
    {
        if (!cbox_check_fb_channel(fb, cmd->command, error))
            return FALSE;
        
        for(GList *p = song->tracks; p; p = g_list_next(p))
        {
            struct cbox_track *trk = p->data;
            if (!cbox_execute_on(fb, NULL, "/track", "sio", error, trk->name, g_list_length(trk->items), trk))
                return FALSE;
        }
        for(GList *p = song->patterns; p; p = g_list_next(p))
        {
            struct cbox_midi_pattern *pat = p->data;
            if (!cbox_execute_on(fb, NULL, "/pattern", "sio", error, pat->name, pat->loop_end, pat))
                return FALSE;
        }
        uint32_t pos = 0;
        for(GList *p = song->master_track_items; p; p = g_list_next(p))
        {
            struct cbox_master_track_item *mti = p->data;
            // Omit dummy item at 0 position.
            if (pos || (mti->timesig_num && mti->timesig_denom) || mti->tempo)
            {
                if (!cbox_execute_on(fb, NULL, "/mti", "ifii", error, pos, mti->tempo, mti->timesig_num, mti->timesig_denom))
                    return FALSE;
            }
            pos += mti->duration_ppqn;
        }
        return cbox_execute_on(fb, NULL, "/loop_start", "i", error, (int)song->loop_start_ppqn) &&
            cbox_execute_on(fb, NULL, "/loop_end", "i", error, (int)song->loop_end_ppqn) &&
            CBOX_OBJECT_DEFAULT_STATUS(song, fb, error);
    }
    else
    if (!strcmp(cmd->command, "/set_loop") && !strcmp(cmd->arg_types, "ii"))
    {
        song->loop_start_ppqn = CBOX_ARG_I(cmd, 0);
        song->loop_end_ppqn = CBOX_ARG_I(cmd, 1);
        return TRUE;
    }
    else
    if (!strcmp(cmd->command, "/set_mti") && !strcmp(cmd->arg_types, "ifii"))
    {
        cbox_song_set_mti(song, CBOX_ARG_I(cmd, 0), CBOX_ARG_F(cmd, 1), CBOX_ARG_I(cmd, 2), CBOX_ARG_I(cmd, 3));
        return TRUE;
    }
    else
    if (!strcmp(cmd->command, "/clear") && !strcmp(cmd->arg_types, ""))
    {
        cbox_song_clear(song);
        return TRUE;
    }
    else
    if (!strcmp(cmd->command, "/add_track") && !strcmp(cmd->arg_types, ""))
    {
        if (!cbox_check_fb_channel(fb, cmd->command, error))
            return FALSE;
        
        struct cbox_track *track = cbox_track_new(CBOX_GET_DOCUMENT(song));
        cbox_song_add_track(song, track);
        if (!cbox_execute_on(fb, NULL, "/uuid", "o", error, track))
        {
            CBOX_DELETE(track);
            return FALSE;
        }
        
        return TRUE;
    }
    else
    if (!strcmp(cmd->command, "/load_pattern") && !strcmp(cmd->arg_types, "si"))
    {
        if (!cbox_check_fb_channel(fb, cmd->command, error))
            return FALSE;
        
        struct cbox_midi_pattern *pattern = cbox_midi_pattern_load(song, CBOX_ARG_S(cmd, 0), CBOX_ARG_I(cmd, 1), app.engine->master->ppqn_factor);
        if (!cbox_execute_on(fb, NULL, "/uuid", "o", error, pattern))
        {
            CBOX_DELETE(pattern);
            return FALSE;
        }
        
        return TRUE;
    }
    else
    if (!strcmp(cmd->command, "/load_track") && !strcmp(cmd->arg_types, "si"))
    {
        if (!cbox_check_fb_channel(fb, cmd->command, error))
            return FALSE;
        
        struct cbox_midi_pattern *pattern = cbox_midi_pattern_load_track(song, CBOX_ARG_S(cmd, 0), CBOX_ARG_I(cmd, 1), app.engine->master->ppqn_factor);
        if (!cbox_execute_on(fb, NULL, "/uuid", "o", error, pattern))
        {
            CBOX_DELETE(pattern);
            return FALSE;
        }
        
        return TRUE;
    }
    else
    if (!strcmp(cmd->command, "/load_metronome") && !strcmp(cmd->arg_types, "i"))
    {
        if (!cbox_check_fb_channel(fb, cmd->command, error))
            return FALSE;
        
        struct cbox_midi_pattern *pattern = cbox_midi_pattern_new_metronome(song, CBOX_ARG_I(cmd, 0), app.engine->master->ppqn_factor);
        if (!cbox_execute_on(fb, NULL, "/uuid", "o", error, pattern))
        {
            CBOX_DELETE(pattern);
            return FALSE;
        }
        
        return TRUE;
    }
    else
    if (!strcmp(cmd->command, "/load_blob") && !strcmp(cmd->arg_types, "bi"))
    {
        if (!cbox_check_fb_channel(fb, cmd->command, error))
            return FALSE;
        
        struct cbox_midi_pattern *pattern = cbox_midi_pattern_new_from_blob(song, CBOX_ARG_B(cmd, 0), CBOX_ARG_I(cmd, 1), app.engine->master->ppqn_factor);
        if (!cbox_execute_on(fb, NULL, "/uuid", "o", error, pattern))
        {
            CBOX_DELETE(pattern);
            return FALSE;
        }
        
        return TRUE;
    }
    else
        return cbox_object_default_process_cmd(ct, fb, cmd, error);
    return TRUE;
}
Exemple #12
0
gboolean fxchain_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
    struct fxchain_module *m = (struct fxchain_module *)ct->user_data;
    const char *subcommand = NULL;
    int index = 0;
    
    //EFFECT_PARAM("/module_count", "i", stages, int, , 1, 12) else
    if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
    {
        if (!cbox_check_fb_channel(fb, cmd->command, error))
            return FALSE;
        for (uint32_t i = 0; i < m->module_count; i++)
        {
            gboolean res = FALSE;
            if (m->modules[i])
                res = cbox_execute_on(fb, NULL, "/module", "ss", error, m->modules[i]->engine_name, m->modules[i]->instance_name);
            else
                res = cbox_execute_on(fb, NULL, "/module", "ss", error, "", "");
            if (!res)
                return FALSE;
            res = cbox_execute_on(fb, NULL, "/bypass", "ii", error, i + 1, m->modules[i] ? m->modules[i]->bypass : 0);
        }
        return CBOX_OBJECT_DEFAULT_STATUS(&m->module, fb, error);
    }
    else if (cbox_parse_path_part_int(cmd, "/module/", &subcommand, &index, 1, m->module_count, error))
    {
        if (!subcommand)
            return FALSE;
        return cbox_module_slot_process_cmd(&m->modules[index - 1], fb, cmd, subcommand, CBOX_GET_DOCUMENT(&m->module), m->module.rt, m->module.engine, error);
    }
    else if (!strcmp(cmd->command, "/insert") && !strcmp(cmd->arg_types, "i"))
    {
        int pos = CBOX_ARG_I(cmd, 0) - 1;
        struct cbox_module **new_modules = malloc((m->module_count + 1) * sizeof(struct cbox_module *));
        memcpy(new_modules, m->modules, pos * sizeof(struct cbox_module *));
        new_modules[pos] = NULL;
        memcpy(new_modules + pos + 1, m->modules + pos, (m->module_count - pos) * sizeof(struct cbox_module *));
        void *old_modules = cbox_rt_swap_pointers_and_update_count(m->module.rt, (void **)&m->modules, new_modules, &m->module_count, m->module_count + 1);
        free(old_modules);
        return TRUE;
    }
    else if (!strcmp(cmd->command, "/delete") && !strcmp(cmd->arg_types, "i"))
    {
        int pos = CBOX_ARG_I(cmd, 0) - 1;
        struct cbox_module **new_modules = malloc((m->module_count + 1) * sizeof(struct cbox_module *));
        memcpy(new_modules, m->modules, pos * sizeof(struct cbox_module *));
        memcpy(new_modules + pos, m->modules + pos + 1, (m->module_count - pos - 1) * sizeof(struct cbox_module *));
        struct cbox_module *deleted_module = m->modules[pos];
        void *old_modules = cbox_rt_swap_pointers_and_update_count(m->module.rt, (void **)&m->modules, new_modules, &m->module_count, m->module_count - 1);
        free(old_modules);
        if (deleted_module)
            CBOX_DELETE(deleted_module);
        return TRUE;
    }
    else if (!strcmp(cmd->command, "/move") && !strcmp(cmd->arg_types, "ii"))
    {
        int oldpos = CBOX_ARG_I(cmd, 0) - 1;
        int newpos = CBOX_ARG_I(cmd, 1) - 1;
        fxchain_move(m, oldpos, newpos);
    }
    else
        return cbox_object_default_process_cmd(ct, fb, cmd, error);
    return TRUE;
}