/* * This file is part of tk707. * * Copyright (C) 2000, 2001, 2002, 2003, 2004 Chris Willing and Pierre Saramito * * tk707 is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Foobar 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include "util707.h" #include "nix_bit.h" TK707 *tk707; #define tk7_get_pattern(tk707,group,pattern) \ (((TK707*)(tk707))->ptree[((TK707*)(tk707))->mbank] + 16*(group) + (pattern)) typedef struct { char *cmdname; Tcl_ObjCmdProc *cmdProc; } NewCmd; /* Strings to hold scripts for C code evaluation */ extern char tcl_ports[]; extern char tcl_title_defs[]; extern char tcl_score_defs[]; extern char tcl_defs[]; extern char tcl_gui[]; extern char tcl_title[]; extern char tcl_score[]; extern char tcl_procs[]; extern char tcl_help[]; extern char tcl_tk707[]; /* * Insert names tcl scripts generated by tcl2c here */ #ifndef not_compile_tcl char *scripts[]={ tcl_ports, tcl_title_defs, tcl_score_defs, tcl_defs, tcl_gui, tcl_title, tcl_score, tcl_procs, tcl_help, tcl_tk707, (char*)NULL }; #endif int cm2pix(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int set_patbuf(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int copy_patbuf(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int group_step_lengths(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int set_last_step(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int get_last_step(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int port_list(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int port_setcheck(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int pattern_items(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int pattern_play(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int Init707(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int clear_tree(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int clear_pattern(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int set_sounds(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int timer_status(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int pat_stop(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int set_tempo(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int set_vols(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int get_pat_tick(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int Exit707(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int cartridge_incr(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int add_note(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int set_scale(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int get_scale(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int group_scale(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int get_pattern_properties(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int set_properties(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int get_properties(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int set_flam(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int get_flam(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int set_shuffle(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int get_shuffle(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int set_pattern_comment(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int get_pattern_comment(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int group_pattern_properties(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int start_note_play(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int stop_note_play(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int start_note_test(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); int stop_note_test(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); NewCmd cmdlist[]={ { "tk7_init", Init707}, { "tk7_cm2pix", cm2pix}, { "tk7_set_patbuf", set_patbuf}, { "tk7_copy_patbuf", copy_patbuf}, { "tk7_set_last_step", set_last_step}, { "tk7_get_last_step", get_last_step}, { "tk7_group_step_lengths", group_step_lengths}, { "tk7_clear_tree", clear_tree}, { "tk7_port_list", port_list}, { "tk7_port_setcheck", port_setcheck}, { "tk7_clear_pattern", clear_pattern}, { "tk7_pattern_items", pattern_items}, { "tk7_set_sounds", set_sounds}, { "tk7_timer_status", timer_status}, { "tk7_set_tempo", set_tempo}, { "tk7_pattern_play", pattern_play}, { "tk7_set_vols", set_vols}, { "tk7_pattern_stop", pat_stop}, { "tk7_get_pat_tick", get_pat_tick}, { "exit707", Exit707}, { "tk7_cartridge_incr", cartridge_incr}, { "tk7_add_note", add_note}, { "tk7_set_scale", set_scale}, { "tk7_get_scale", get_scale}, { "tk7_group_scale", group_scale}, { "tk7_get_pattern_properties", get_pattern_properties}, { "tk7_set_properties", set_properties}, { "tk7_get_properties", get_properties}, { "tk7_set_flam", set_flam}, { "tk7_get_flam", get_flam}, { "tk7_set_shuffle", set_shuffle}, { "tk7_get_shuffle", get_shuffle}, { "tk7_group_pattern_properties", group_pattern_properties}, { "tk7_start_note_play", start_note_play}, { "tk7_stop_note_play", stop_note_play}, { "tk7_start_note_test", start_note_test}, { "tk7_stop_note_test", stop_note_test}, { "tk7_set_pattern_comment", set_pattern_comment}, { "tk7_get_pattern_comment", get_pattern_comment}, /**/ { NULL, NULL} }; /* * Return: * 0 if all OK * 1 => just asked for list of ports (supplied it, now exit) * 2 => need a port description (run port selector gui) * 3 => something weird so exit */ int Init707(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { extern char *optarg; int c, res; char *portdesc; int i, bank, pattern; int argc; char *argv[10]; Tcl_Obj *temp=NULL, *descObj=NULL; /* Create a string array for getopt() */ argc = objc; for(c=0;c 0 ) { switch(c) { case 'p': portdesc = optarg; break; case 'h': usage(); return TCL_OK; break; case 'l': { char **cpinfo; int i, ret = get_clientsports(&cpinfo); for(i=0;iptree[i])) < 0 ) { Tcl_SetResult(interp, "Couldn't pattern_el_init", TCL_VOLATILE); return TCL_ERROR; } } tk707->patbuf = NULL; if( alsa_setup(tk707, portdesc, NULL) < 0 ) { Tcl_SetResult(interp, "Couldn't seq707_context_init", TCL_VOLATILE); #ifdef OLD return TCL_ERROR; #endif // OLD } Tcl_LinkVar(interp, "midi_channel", (char*)(&(tk707->ctxp_p->midichannel)), TCL_LINK_INT); Tcl_LinkVar(interp, "midi_channel", (char*)(&(tk707->ctxp_c->midichannel)), TCL_LINK_INT); /* Set the default instrument to volume fader map */ tk707->volmap[0] = 1; tk707->volmap[1] = 1; tk707->volmap[2] = 2; tk707->volmap[3] = 2; tk707->volmap[4] = 3; tk707->volmap[5] = 4; tk707->volmap[6] = 5; tk707->volmap[7] = 6; tk707->volmap[8] = 6; tk707->volmap[9] = 7; tk707->volmap[10] = 7; tk707->volmap[11] = 8; tk707->volmap[12] = 8; tk707->volmap[13] = 8; tk707->volmap[14] = 9; tk707->volmap[15] = 10; /* delay property initilaiztion */ for (i = 0; i < 16; i++) { tk707->have_delay[i] = false; } /* Inialisation was completed OK */ Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); return TCL_OK; } int Exit707(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { snd_seq_close(tk707->ctxp_p->handle); snd_seq_close(tk707->ctxp_c->handle); return TCL_OK; } /* * Set tk707->patbuf to point to PatternElement given by group/pattern args. */ int set_patbuf( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int pattern, group; if( objc != 3 ) { Tcl_SetResult(interp, "Wrong #args", TCL_VOLATILE); return TCL_ERROR; } if( Tcl_GetIntFromObj(interp, objv[1], &group) != TCL_OK ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &pattern) != TCL_OK ) return TCL_ERROR; tk707->patbuf = tk707->ptree[tk707->mbank] + (16*group+pattern); return TCL_OK; } /* * Copy elements at tk707->copybuf to new pattern given by group/pattern args. */ int copy_patbuf( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; PatternElement *to; int pattern, group, merge; tk707_get_int3_macro(interp,objc,objv,group,pattern,merge); if( ! tk707->patbuf ) { Tcl_SetResult(interp, "Nothing in copy buffer", TCL_VOLATILE); return TCL_ERROR; } to = tk707->ptree[tk707->mbank] + (16*group+pattern); if( to == tk707->patbuf ) return TCL_OK; el_copy_pattern(to, tk707->patbuf, merge); return TCL_OK; } /* * Set/get the last step to be used for a given pattern. * Return the new last step value */ int set_last_step( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int pattern, group, stepval, i; tk707_get_int3_macro(interp,objc,objv,group,pattern,stepval); pattern_set_length(tk707->ptree[tk707->mbank] + (16*group+pattern), stepval); Tcl_SetObjResult(interp, Tcl_NewIntObj(stepval)); return TCL_OK; } int get_last_step( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int pattern, group, stepval; tk707_get_int2_macro(interp,objc,objv,group,pattern); stepval = pattern_get_length(tk707->ptree[tk707->mbank] + (16*group+pattern)); Tcl_SetObjResult(interp, Tcl_NewIntObj(stepval)); return TCL_OK; } /* * Set/get the scale to be used for a given pattern. */ int set_scale( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int pattern, group, scaleval, i; tk707_get_int3_macro(interp,objc,objv,group,pattern,scaleval); pattern_set_scale (tk707->ptree[tk707->mbank] + (16*group+pattern), scaleval); Tcl_SetObjResult(interp, Tcl_NewIntObj(scaleval)); return TCL_OK; } int get_scale( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int pattern, group, scaleval; tk707_get_int2_macro(interp,objc,objv,group,pattern); scaleval = pattern_get_scale(tk707->ptree[tk707->mbank] + (16*group+pattern)); Tcl_SetObjResult(interp, Tcl_NewIntObj(scaleval)); return TCL_OK; } /* * Set/get the flam to be used for a given pattern. */ int set_flam( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int pattern, group, flamval, i; tk707_get_int3_macro(interp,objc,objv,group,pattern,flamval); pattern_set_flam (tk707->ptree[tk707->mbank] + (16*group+pattern), flamval); Tcl_SetObjResult(interp, Tcl_NewIntObj(flamval)); return TCL_OK; } int get_flam( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int pattern, group, flamval; tk707_get_int2_macro(interp,objc,objv,group,pattern); flamval = pattern_get_flam(tk707->ptree[tk707->mbank] + (16*group+pattern)); Tcl_SetObjResult(interp, Tcl_NewIntObj(flamval)); return TCL_OK; } /* * Set/get the shuffle to be used for a given pattern. */ int set_shuffle( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int pattern, group, shuffleval, i; tk707_get_int3_macro(interp,objc,objv,group,pattern,shuffleval); pattern_set_shuffle (tk707->ptree[tk707->mbank] + (16*group+pattern), shuffleval); Tcl_SetObjResult(interp, Tcl_NewIntObj(shuffleval)); return TCL_OK; } int get_shuffle( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int pattern, group, shuffleval; tk707_get_int2_macro(interp,objc,objv,group,pattern); shuffleval = pattern_get_shuffle(tk707->ptree[tk707->mbank] + (16*group+pattern)); Tcl_SetObjResult(interp, Tcl_NewIntObj(shuffleval)); return TCL_OK; } /* * Set/get the comment for a given pattern. */ int set_pattern_comment( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int pattern, group; char* commentval; tk707_get_int2str1_macro(interp,objc,objv,group,pattern,commentval); pattern_set_comment (tk707->ptree[tk707->mbank] + (16*group+pattern), commentval); Tcl_SetObjResult(interp, Tcl_NewStringObj(commentval, strlen(commentval))); return TCL_OK; } int get_pattern_comment( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int pattern, group; char* commentval; tk707_get_int2_macro(interp,objc,objv,group,pattern); commentval = pattern_get_comment(tk707->ptree[tk707->mbank] + (16*group+pattern)); Tcl_SetObjResult(interp, Tcl_NewStringObj(commentval, strlen(commentval))); return TCL_OK; } /* * Return a list of steplength values for all patterns in a given group */ int group_step_lengths( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; Tcl_Obj *res; int pattern, group, stepcount; tk707_get_int1_macro(interp,objc,objv,group); res = Tcl_NewListObj(0, NULL); for(pattern=0;pattern<16;pattern++) { stepcount = pattern_get_length(tk707->ptree[tk707->mbank] + (16*group+pattern)); Tcl_ListObjAppendElement(interp, res, Tcl_NewIntObj(stepcount)); } Tcl_SetObjResult(interp, res); return TCL_OK; } /* * Return a list of scale values for all patterns in a given group */ int group_scale( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; Tcl_Obj *res; int pattern, group, scalecount; tk707_get_int1_macro(interp,objc,objv,group); res = Tcl_NewListObj(0, NULL); for(pattern=0;pattern<16;pattern++) { scalecount = pattern_get_scale(tk707->ptree[tk707->mbank] + (16*group+pattern)); Tcl_ListObjAppendElement(interp, res, Tcl_NewIntObj(scalecount)); } Tcl_SetObjResult(interp, res); return TCL_OK; } /* * Return a list of list pattern properties for all patterns in a given group * { {length scale flam shuffle}*16 } */ int group_pattern_properties( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int pattern, group; Tcl_Obj *res = Tcl_NewListObj(0, NULL); tk707_get_int1_macro(interp,objc,objv,group); for(pattern = 0; pattern < 16; pattern++) { int length = pattern_get_length (tk707->ptree[tk707->mbank] + (16*group+pattern)); int scale = pattern_get_scale (tk707->ptree[tk707->mbank] + (16*group+pattern)); int flam = pattern_get_flam (tk707->ptree[tk707->mbank] + (16*group+pattern)); int shuffle = pattern_get_shuffle(tk707->ptree[tk707->mbank] + (16*group+pattern)); char* comment = pattern_get_comment(tk707->ptree[tk707->mbank] + (16*group+pattern)); Tcl_Obj *prop_list = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, prop_list, Tcl_NewIntObj(length)); Tcl_ListObjAppendElement(interp, prop_list, Tcl_NewIntObj(scale)); Tcl_ListObjAppendElement(interp, prop_list, Tcl_NewIntObj(flam)); Tcl_ListObjAppendElement(interp, prop_list, Tcl_NewIntObj(shuffle)); Tcl_ListObjAppendElement(interp, prop_list, Tcl_NewStringObj(comment,strlen(comment))); Tcl_ListObjAppendElement(interp, res, prop_list); } Tcl_SetObjResult(interp, res); return TCL_OK; } int clear_tree(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; pattern_el_clearall(tk707->ptree[tk707->mbank]); return TCL_OK; } int clear_pattern(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int pattern, group, i; MidiElement *base; tk707_get_int2_macro(interp,objc,objv,group, pattern); for(i=0;i<16;i++) { step_el_clear((tk707->ptree[tk707->mbank] + (16*group+pattern))->mel+i); } return TCL_OK; } int set_sounds(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int i; char index[8]; for(i=1;i<17;i++) { sprintf(index, "%d,note", i); tk707->sounds[i-1] = atoi(Tcl_GetVar2(interp, "sound", index, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG)); } return TCL_OK; } int set_tempo(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; seq707_context_t *ctxp = tk707->ctxp_p; int diff, newticks; snd_seq_event_t ev; tk707_get_int1_macro(interp,objc,objv, newticks); ctxp->tempo = (unsigned int)((((double)(old_tick_per_quarter * 500000))/(double)newticks)); do_tempo_set(ctxp, ctxp->tempo); ctxp->ppq = newticks; return TCL_OK; } #ifdef HAVE_ALSA9 int timer_status(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; seq707_context_t *ctxp = tk707->ctxp_p; snd_seq_queue_status_t *status; snd_seq_queue_status_alloca(&status); snd_seq_get_queue_status(ctxp->handle, ctxp->dest_queue, status); Tcl_SetObjResult(interp, Tcl_NewIntObj(snd_seq_queue_status_get_tick_time(status))); return TCL_OK; } #else /* !HAVE_ALSA9 */ int timer_status(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; seq707_context_t *ctxp = tk707->ctxp_p; snd_seq_queue_status_t status; snd_seq_get_queue_status(ctxp->handle, ctxp->dest_queue, &status); Tcl_SetObjResult(interp, Tcl_NewIntObj(status.tick)); return TCL_OK; } #endif /* HAVE_ALSA9 */ #ifdef HAVE_ALSA9 int get_pat_tick(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; seq707_context_t *ctxp = tk707->ctxp_p; snd_seq_queue_status_t *status; int result; snd_seq_queue_status_alloca(&status); snd_seq_get_queue_status(ctxp->handle, ctxp->dest_queue, status); result = 16 - ((ctxp->currticktime - snd_seq_queue_status_get_tick_time(status))/old_tick_per_sixtennth); Tcl_SetObjResult(interp, Tcl_NewIntObj(result)); return TCL_OK; } #else /* !HAVE_ALSA9 */ int get_pat_tick(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; seq707_context_t *ctxp = tk707->ctxp_p; snd_seq_queue_status_t status; int result; snd_seq_get_queue_status(ctxp->handle, ctxp->dest_queue, &status); result = 16 - ((ctxp->currticktime-status.tick)/old_tick_per_sixtennth); Tcl_SetObjResult(interp, Tcl_NewIntObj(result)); return TCL_OK; } #endif /* HAVE_ALSA9 */ static int ponderated_velocity (int volume_master, int volume_accent, double accent_factor, int volume_instr, double instr_factor) { double note_factor = volume_master*(volume_instr*instr_factor)*(volume_accent*accent_factor)/(100.*100.*100.); return (int)(127 * note_factor + 0.5); } static int compute_velocity (int prop, int volume_master, int volume_accent, int volume_instr) { double instr_factor; double accent_factor; double note_factor; int velocity; if (prop & zero_velocity) { instr_factor = 0; accent_factor = 0; } else { instr_factor = 1; if (prop & strong_accent_velocity) { accent_factor = 1; } else if (prop & weak_accent_velocity) { accent_factor = 2/3.0; } else { accent_factor = 1/3.0; } } return ponderated_velocity (volume_master, volume_accent, accent_factor, volume_instr, instr_factor); } static void c_start_note (TK707 *tk707, int keynum, int midi_note, int prop) { int volume_accent = tk707->volumes [0]; int volume_master = tk707->volumes [11]; int volume_instr = tk707->volumes [tk707->volmap[keynum]]; int velocity = compute_velocity (prop, volume_master,volume_accent,volume_instr); seq707_context_t *ctxp = tk707->ctxp_c; static int have_start = 0; snd_seq_queue_status_t *status; int midich; int cur_tick; #ifdef HAVE_ALSA9 snd_seq_queue_status_alloca(&status); snd_seq_get_queue_status(ctxp->handle, ctxp->dest_queue, status); cur_tick = snd_seq_queue_status_get_tick_time(status); #else snd_seq_get_queue_status(ctxp->handle, ctxp->dest_queue, status); cur_tick = status->tick; #endif if ( cur_tick > ctxp->currticktime ) { ctxp->currticktime = cur_tick; } midich = ctxp->midichannel; if (!have_start) { alsa_timer_start (ctxp); have_start = true; } else { alsa_timer_cont (ctxp); } do_noteon (ctxp, midich, midi_note, velocity); if (prop & fla_property) { /* note have a fla */ int flam_interval = 2; /* use default, without pattern properties */ int tick_per_flam = flam_interval * tick_flam_duration; ctxp->currticktime += tick_per_flam; do_noteon (ctxp, midich, midi_note, velocity); } #ifdef HAVE_ALSA9 snd_seq_drain_output(ctxp->handle); #else snd_seq_flush_output(ctxp->handle); #endif } static void c_stop_note (TK707 *tk707, int midi_note) { seq707_context_t *ctxp = tk707->ctxp_c; snd_seq_queue_status_t *status; int midich; int cur_tick; #ifdef HAVE_ALSA9 snd_seq_queue_status_alloca(&status); snd_seq_get_queue_status(ctxp->handle, ctxp->dest_queue, status); cur_tick = snd_seq_queue_status_get_tick_time(status); #else snd_seq_get_queue_status(ctxp->handle, ctxp->dest_queue, status); cur_tick = status->tick; #endif if ( cur_tick > ctxp->currticktime ) { ctxp->currticktime = cur_tick; } midich = ctxp->midichannel; do_noteon (ctxp, midich, midi_note, 0); /* ctxp->currticktime += old_tick_per_quarter; */ #ifdef HAVE_ALSA9 snd_seq_drain_output(ctxp->handle); #else snd_seq_flush_output(ctxp->handle); #endif alsa_timer_stop(ctxp); } /* * Start a note down the "realtime" queue */ int start_note_play(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int keynum, prop, midi_note; tk707_get_int2_macro(interp,objc,objv, keynum, prop); midi_note = tk707->sounds[keynum]; c_start_note (tk707, keynum, midi_note, prop); return TCL_OK; } /* * Stop a note down the "realtime" queue */ int stop_note_play(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int keynum, midi_note; tk707_get_int1_macro(interp,objc,objv, keynum); midi_note = tk707->sounds[keynum]; c_stop_note (tk707, midi_note); return TCL_OK; } /* * Start a note down the "realtime" queue using a supplied midi note value * (instead of looking it up as in note_play() ). */ int start_note_test(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int keynum, midi_note; tk707_get_int2_macro(interp,objc,objv, keynum, midi_note); c_start_note (tk707, keynum, midi_note, 0); return TCL_OK; } /* * Stop a note down the "realtime" queue using a supplied midi note value * (instead of looking it up as in note_play() ). */ int stop_note_test(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int keynum, midi_note; tk707_get_int2_macro(interp,objc,objv, keynum, midi_note); c_stop_note (tk707, midi_note); return TCL_OK; } int pat_stop(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; seq707_context_t *ctxp = tk707->ctxp_p; snd_seq_drain_output(ctxp->handle); return TCL_OK; } int pattern_play(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; seq707_context_t *ctxp = tk707->ctxp_p; snd_seq_queue_status_t *status = 0; int cur_tick; int group, pattern, step, stepcount, scale, midich, dur; PatternElement *current_pattern; int volume_master, volume_accent, flam_interval; int tick_per_step, tick_per_flam; tk707_get_int2_macro(interp,objc,objv, group, pattern); volume_accent = tk707->volumes [0]; volume_master = tk707->volumes [11]; current_pattern = tk7_get_pattern(tk707,group,pattern); stepcount = pattern_get_length(current_pattern); scale = pattern_get_scale (current_pattern); flam_interval = pattern_get_flam (current_pattern); tick_per_step = old_tick_per_step_off_scale[scale] + old_tick_per_note_on; tick_per_flam = flam_interval * tick_flam_duration; if (old_tick_per_note_on < 4*tick_flam_duration) { fprintf (stderr, "FATAL: invalid flam/delay configuration\n"); exit (1); } #ifdef HAVE_ALSA9 snd_seq_queue_status_alloca(&status); snd_seq_get_queue_status(ctxp->handle, ctxp->dest_queue, status); cur_tick = snd_seq_queue_status_get_tick_time(status); #else snd_seq_get_queue_status(ctxp->handle, ctxp->dest_queue, status); cur_tick = status->tick; #endif if( cur_tick > ctxp->currticktime ) { ctxp->currticktime = cur_tick; } midich = ctxp->midichannel; alsa_timer_cont (ctxp); for (step = 0; step < stepcount; step++) { MidiElement *instrument_set = current_pattern->mel [step]; MidiElement *instrument; if (!instrument_set) { /* No notes at this step. Just update timer. */ ctxp->currticktime += tick_per_step; continue; } /* * note-on */ for (instrument = instrument_set; instrument; instrument = instrument->next) { int idx_note = el_get_note (instrument); int midi_note = tk707->sounds [idx_note]; int volume_instr = tk707->volumes [tk707->volmap[idx_note]]; int velocity = compute_velocity (el_get_properties(instrument), volume_master,volume_accent,volume_instr); do_noteon (ctxp, midich, midi_note, velocity); } ctxp->currticktime += tick_per_flam; /* * flam */ for (instrument = instrument_set; instrument; instrument = instrument->next) { if (have_fla (instrument)) { int idx_note = el_get_note (instrument); int midi_note = tk707->sounds [idx_note]; int volume_instr = tk707->volumes [tk707->volmap[idx_note]]; int velocity = compute_velocity (el_get_properties(instrument), volume_master,volume_accent,volume_instr); do_noteon (ctxp, midich, midi_note, velocity); } } ctxp->currticktime += old_tick_per_note_on - tick_per_flam; /* * note-off when delay */ for (instrument = instrument_set; instrument; instrument = instrument->next) { int idx_note = el_get_note (instrument); if (tk707->have_delay [idx_note]) { int midi_note = tk707->sounds [idx_note]; do_noteoff (ctxp, midich, midi_note, 127); } } ctxp->currticktime += old_tick_per_step_off_scale [scale]; } #ifdef HAVE_ALSA9 snd_seq_drain_output(ctxp->handle); #else snd_seq_flush_output(ctxp->handle); #endif alsa_timer_stop(ctxp); dur = (int)(500*((double)(ctxp->currticktime - cur_tick)/(double)ctxp->ppq)); Tcl_SetObjResult(interp, Tcl_NewIntObj(dur - tick_per_step)); return TCL_OK; } int cartridge_incr(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; tk707->mbank = ++tk707->mbank % 3; Tcl_SetObjResult(interp, Tcl_NewIntObj(tk707->mbank)); return TCL_OK; } /* Add (or delete if already exists) a new note as a midi element */ int add_note(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int group, pattern, step, note; TK707 *tk707 = (TK707*)clientData; MidiElement *temp; tk707_get_int4_macro(interp,objc,objv, group, pattern, step, note); if( (temp=step_add_el(tk707->ptree[tk707->mbank], group, pattern, step, note - 1)) == NULL ) { Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); return TCL_OK; } else { Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1)); return TCL_OK; } /* printf("Added note %d at group %d, pattern %d, step %d, (cart %d)\n", el_get_note(temp), group, pattern, step, tk707->mbank); pattern_display_els(tk707->ptree[tk707->mbank], group, pattern); */ } /* get note properties in a midi element * if note does not exists, return 0 */ int get_properties(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int group, pattern, step, note, prop; TK707 *tk707 = (TK707*)clientData; MidiElement *temp; tk707_get_int4_macro(interp,objc,objv, group, pattern, step, note); temp = step_get_el(tk707->ptree[tk707->mbank], group, pattern, step, note - 1); if (!temp) { Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); } else { Tcl_SetObjResult(interp, Tcl_NewIntObj(el_get_properties(temp))); } return TCL_OK; } /* set note properties in a midi element * if note does not exists yet, insert it */ int set_properties(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int group, pattern, step, note, prop; TK707 *tk707 = (TK707*)clientData; MidiElement *temp; tk707_get_int5_macro(interp,objc,objv, group, pattern, step, note, prop); temp = step_get_el(tk707->ptree[tk707->mbank], group, pattern, step, note - 1); if (!temp) { temp = step_get_el(tk707->ptree[tk707->mbank], group, pattern, step, note - 1); } el_set_properties (temp, prop); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1)); return TCL_OK; } /* Return a list of instruments for the specified pattern step */ int pattern_items(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; Tcl_Obj *res; int group, pattern, step, i; int items[17]; tk707_get_int3_macro(interp,objc,objv, group, pattern, step); res = Tcl_NewListObj(0, NULL); if (group == -1) { group = 0; } if (pattern == -1) { pattern = 0; } el_get_step_elements((tk707->ptree[tk707->mbank] + (16*group+pattern))->mel + step, items); for(i=0;items[i]>=0;i++) { Tcl_ListObjAppendElement(interp, res, Tcl_NewIntObj(items[i] + 1)); } Tcl_SetObjResult(interp, res); return TCL_OK; } /* Return a list of note properties for the specified pattern step */ int get_pattern_properties(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; Tcl_Obj *res; int group, pattern, step, i; int items[17]; tk707_get_int3_macro(interp,objc,objv, group, pattern, step); res = Tcl_NewListObj(0, NULL); if (group == -1) { group = 0; } if (pattern == -1) { pattern = 0; } el_get_step_properties((tk707->ptree[tk707->mbank] + (16*group+pattern))->mel + step, items); for(i=0;items[i]>=0;i++) { Tcl_ListObjAppendElement (interp, res, Tcl_NewIntObj(items[i])); } Tcl_SetObjResult(interp, res); return TCL_OK; } /* Update volume fader settings */ int set_vols(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; int val, i; if( objc != 13 ) return TCL_ERROR; for(i=1;ivolumes[i-1] = val; } return TCL_OK; } /* Check whether alsa ports have been set */ int port_setcheck(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; Tcl_Obj *temp=NULL; temp = Tcl_ObjGetVar2(interp, Tcl_NewStringObj("tkxox", strlen("tkxox")), Tcl_NewStringObj("ALSA_OUTPORT", strlen("ALSA_OUTPORT")), TCL_GLOBAL_ONLY); if( !temp ) { Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); return TCL_OK; } else { Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1)); return TCL_OK; } return TCL_OK; } /* Construct a list of ALSA midi ports on the system. */ #ifdef HAVE_ALSA9 int port_list(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; Tcl_Obj *res, *items[16]={NULL}; int i, client, port, io; snd_seq_client_info_t *cinfo; snd_seq_port_info_t *pinfo; snd_seq_t *handle; if( objc != 2 ) { Tcl_SetResult(interp, "Wrong #args", TCL_VOLATILE); return TCL_ERROR; } if( Tcl_GetIntFromObj(interp, objv[1], &io) != TCL_OK ) return TCL_ERROR; if( snd_seq_open(&handle, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0 ) { return TCL_ERROR; } res = Tcl_NewListObj(0, NULL); snd_seq_client_info_alloca(&cinfo); snd_seq_port_info_alloca(&pinfo); i = 0; snd_seq_client_info_set_client(cinfo, 0); while (snd_seq_query_next_client(handle, cinfo) >= 0) { client = snd_seq_client_info_get_client(cinfo); snd_seq_port_info_set_client(pinfo, client); snd_seq_port_info_set_port(pinfo, -1); while (snd_seq_query_next_port(handle, pinfo) >= 0) { unsigned int cap; if( io > 0 ) cap = (SND_SEQ_PORT_CAP_SUBS_WRITE|SND_SEQ_PORT_CAP_WRITE); else cap = (SND_SEQ_PORT_CAP_SUBS_READ|SND_SEQ_PORT_CAP_READ); if( (snd_seq_port_info_get_capability(pinfo) & cap) == cap ) { const char *name; port = snd_seq_port_info_get_port(pinfo); items[i] = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, items[i], Tcl_NewIntObj(client)); Tcl_ListObjAppendElement(interp, items[i], Tcl_NewIntObj(port)); name = snd_seq_port_info_get_name(pinfo); Tcl_ListObjAppendElement(interp, items[i], Tcl_NewStringObj(name, strlen(name))); name = snd_seq_client_info_get_name(cinfo); Tcl_ListObjAppendElement(interp, items[i], Tcl_NewStringObj(name, strlen(name))); Tcl_ListObjAppendElement(interp, res, items[i]); i++; } } } Tcl_SetObjResult(interp, res); return TCL_OK; } #else /* !HAVE_ALSA9 */ int port_list(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; Tcl_Obj *res, *items[17]={NULL}; int i, client, port, io; snd_seq_client_info_t cinfo; snd_seq_port_info_t pinfo; snd_seq_system_info_t sysinfo; snd_seq_t *handle; tk707_get_int1_macro(interp,objc,objv, io); if( snd_seq_open(&handle, SND_SEQ_OPEN) < 0 ) { return TCL_ERROR; } if( snd_seq_system_info(handle, &sysinfo) < 0 ) { return TCL_ERROR; } res = Tcl_NewListObj(0, NULL); i = 0; for(client=0;client 0 ) cap = (SND_SEQ_PORT_CAP_SUBS_WRITE|SND_SEQ_PORT_CAP_WRITE); else cap = (SND_SEQ_PORT_CAP_SUBS_READ|SND_SEQ_PORT_CAP_READ); if( (pinfo.capability & cap) == cap ) { items[i] = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, items[i], Tcl_NewIntObj(pinfo.client)); Tcl_ListObjAppendElement(interp, items[i], Tcl_NewIntObj(pinfo.port)); Tcl_ListObjAppendElement(interp, items[i], Tcl_NewStringObj(pinfo.name, strlen(pinfo.name))); Tcl_ListObjAppendElement(interp, items[i], Tcl_NewStringObj(cinfo.name, strlen(cinfo.name))); Tcl_ListObjAppendElement(interp, res, items[i]); i++; } } } Tcl_SetObjResult(interp, res); return TCL_OK; } #endif /* HAVE_ALSA9 */ /* Return a given screen distance to pixels */ int cm2pix(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { TK707 *tk707 = (TK707*)clientData; char *rawlen, *widgetpath; Tk_Window tkwin; int pixels; if( objc != 3 ) { Tcl_SetResult(interp, "Wrong #args", TCL_VOLATILE); return TCL_ERROR; } if( (widgetpath=Tcl_GetStringFromObj(objv[1], NULL)) == NULL ) return TCL_ERROR; if( (rawlen=Tcl_GetStringFromObj(objv[2], NULL)) == NULL ) return TCL_ERROR; tkwin = Tk_NameToWindow(interp, widgetpath, Tk_MainWindow(interp)); if( Tk_GetPixels(interp, tkwin, rawlen, &pixels) != TCL_OK ) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewIntObj(pixels)); return TCL_OK; } /* ============================================================================ This is where the commands are registered. Don't change this section! ========================================================================= */ int Init_tk707(Tcl_Interp *interp) { NewCmd *cmdptr=cmdlist; /* We want all (most) of the new commands to have access to * "tk707" structure (via clientData) so create it before * creating all the new commands. */ if( (tk707=(TK707*)calloc(1, sizeof(TK707))) == NULL ) return TCL_ERROR; /* Create the new commands */ while( cmdptr->cmdname != NULL ) { Tcl_CreateObjCommand(interp, cmdptr->cmdname, cmdptr->cmdProc, (ClientData*)tk707, (Tcl_CmdDeleteProc*)NULL); cmdptr++; } Tk_DefineBitmap(interp, Tk_GetUid("nix"), nix_bits, 1, 1); return TCL_OK; } int Init_tk707_Scripts(Tcl_Interp *interp) { int result; char **ptr; result = TCL_OK; #ifndef not_compile_tcl for(ptr=scripts;*ptr!=NULL;ptr++) { if( (result=Tcl_Eval(interp, *ptr)) == TCL_ERROR ) break; } #endif return result; }