From f8ac52e520aa5e20a256a3fd9a649b461f3afeef Mon Sep 17 00:00:00 2001 From: mescalinum Date: Fri, 25 Sep 2009 17:19:25 +0000 Subject: rewrite in C++ svn path=/trunk/externals/ffext/; revision=12451 --- composer/Makefile | 58 +++++ composer/Pattern.cpp | 81 +++++++ composer/Pattern.hpp | 33 +++ composer/PdClasses.cpp | 286 +++++++++++++++++++++++ composer/PdClasses.hpp | 40 ++++ composer/Song.cpp | 42 ++++ composer/Song.hpp | 31 +++ composer/TODO | 4 - composer/Track.cpp | 47 ++++ composer/Track.hpp | 34 +++ composer/arraylist.h | 118 ---------- composer/common.h | 199 ---------------- composer/composer.c | 91 -------- composer/editor.tk | 614 +++++++++++++++++++++++++++++++++++++++++++++++++ composer/makefile | 34 --- composer/pattern.c | 165 ------------- composer/song.c | 104 --------- composer/song_proxy.c | 402 -------------------------------- composer/track.c | 204 ---------------- composer/track_proxy.c | 441 ----------------------------------- composer/window.tk | 614 ------------------------------------------------- 21 files changed, 1266 insertions(+), 2376 deletions(-) create mode 100644 composer/Makefile create mode 100644 composer/Pattern.cpp create mode 100644 composer/Pattern.hpp create mode 100644 composer/PdClasses.cpp create mode 100644 composer/PdClasses.hpp create mode 100644 composer/Song.cpp create mode 100644 composer/Song.hpp delete mode 100644 composer/TODO create mode 100644 composer/Track.cpp create mode 100644 composer/Track.hpp delete mode 100644 composer/arraylist.h delete mode 100644 composer/common.h delete mode 100644 composer/composer.c create mode 100644 composer/editor.tk delete mode 100644 composer/makefile delete mode 100644 composer/pattern.c delete mode 100644 composer/song.c delete mode 100644 composer/song_proxy.c delete mode 100644 composer/track.c delete mode 100644 composer/track_proxy.c delete mode 100644 composer/window.tk diff --git a/composer/Makefile b/composer/Makefile new file mode 100644 index 0000000..dff36ef --- /dev/null +++ b/composer/Makefile @@ -0,0 +1,58 @@ +#!/usr/bin/make + +DEBUG?=0 +OS := $(shell uname -s) +TCL_VERSION := $(shell echo 'puts $$tcl_version' | tclsh) + +ifeq ($(DEBUG),0) + CFLAGS += -O2 +else + CFLAGS += -O0 -g -ggdb -DDEBUG +endif +ifeq ($(OS),Linux) + PDSUF = .pd_linux + PDBUNDLEFLAGS = -shared -rdynamic + LDSOFLAGS = -lm +endif +ifeq ($(OS),Darwin) + PDSUF = .pd_darwin + INCLUDES = -I/Library/Frameworks/Tcl.framework/Headers + PDBUNDLEFLAGS = -bundle -flat_namespace -undefined dynamic_lookup + LDSOFLAGS = -lm +endif +ifeq (MINGW,$(findstring MINGW,$(UNAME))) + PDSUF = .dll + PDBUNDLEFLAGS = -shared + LDSOFLAGS = -lm +endif + +LIBNAME = composer +INCLUDES = -I../../pd/src -I/usr/include #-I/usr/include/tcl$(TCL_VERSION) +CFLAGS += -funroll-loops -fno-operator-names -fno-omit-frame-pointer -falign-functions=16 -Wall -fPIC +CFLAGS += -DPDSUF=\"$(PDSUF)\" +LDSHARED = $(CXX) $(PDBUNDLEFLAGS) + +all: $(LIBNAME)$(PDSUF) + @echo '-----------------------------------------------------------------------------' + @echo ' $(LIBNAME)$(PDSUF) ('`test $(DEBUG) -eq 1 && echo debug || echo release`' build) '\ + '[size: '`ls -gGh $(LIBNAME)$(PDSUF) | cut -d " " -f 3`']' + +clean:: + rm -f $(LIBNAME)$(PDSUF) *.o *~ + +.SUFFIXES: .cpp .o + +SRCS = Song.cpp Pattern.cpp Track.cpp PdClasses.cpp +OBJS = ${SRCS:.cpp=.o} + +Song.o: Song.cpp Song.hpp +Pattern.o: Pattern.cpp Pattern.hpp +Track.o: Track.cpp Track.hpp +PdClass.o: PdClasses.cpp PdClasses.h + +.cpp.o: Makefile + $(CXX) $(CFLAGS) $(INCLUDES) -xc++ -c $< + +$(LIBNAME)$(PDSUF): Makefile $(OBJS) + $(LDSHARED) $(LDSOFLAGS) $(CFLAGS) -xnone $(OBJS) -o $(LIBNAME)$(PDSUF) + diff --git a/composer/Pattern.cpp b/composer/Pattern.cpp new file mode 100644 index 0000000..69c60f4 --- /dev/null +++ b/composer/Pattern.cpp @@ -0,0 +1,81 @@ +#include "Pattern.hpp" + +#include + +using std::cout; +using std::cerr; +using std::endl; + +Pattern::Pattern(int numRows, int numCols, string patternName) +: name(patternName) +{ + Cell empty_cell; + Row empty_row; + + SETSYMBOL(&empty_cell, gensym("empty")); + + while(numCols-- > 0) + { + empty_row.push_back(empty_cell); + } + + columns = empty_row.size(); + + while(numRows-- > 0) + { + Row row(empty_row); + rows.push_back(row); + } +} + +void Pattern::print() +{ + cerr << "---- Pattern: " << name << " ----" << endl; + + char buf[MAXPDSTRING]; + + for(unsigned int i = 0; i < rows.size(); i++) + { + cerr << " Row[" << i << "]: "; + for(unsigned int j = 0; j < rows[i].size(); j++) + { + if(j > 0) cerr << ", "; + atom_string(&rows[i][j], buf, MAXPDSTRING); + cerr << buf << endl; + } + } + + cerr << "---- End pattern (" << name << ") ----" << endl; +} + +void Pattern::resize(int numRows, int numCols) +{ + Cell empty_cell; + Row empty_row; + + SETSYMBOL(&empty_cell, gensym("empty")); + + while(numCols-- > 0) + { + empty_row.push_back(empty_cell); + } + + rows.resize(numRows, empty_row); + + for(unsigned int i = 0; i < rows.size(); i++) + { + rows[i].resize(empty_row.size(), empty_cell); + } + + columns = empty_row.size(); +} + +void Pattern::setCell(int row, int col, Cell cell) +{ + rows[row][col] = cell; +} + +Cell Pattern::getCell(int row, int col) +{ + return rows[row][col]; +} diff --git a/composer/Pattern.hpp b/composer/Pattern.hpp new file mode 100644 index 0000000..1607414 --- /dev/null +++ b/composer/Pattern.hpp @@ -0,0 +1,33 @@ +#ifndef COMPOSER_PATTERN_H_INCLUDED +#define COMPOSER_PATTERN_H_INCLUDED + +#include +#include + +#include + +using std::string; +using std::vector; + +typedef t_atom Cell; + +typedef vector Row; + +class Pattern +{ +private: + string name; + vector rows; + int columns; +public: + Pattern(int numRows, int numCols, string patternName); + void print(); + void resize(int numRows, int numCols); + void setCell(int row, int col, Cell cell); + Cell getCell(int row, int col); + inline const string &getName() {return name;} + inline unsigned int getRows() {return rows.size();} + inline unsigned int getColumns() {return columns;} +}; + +#endif // COMPOSER_PATTERN_H_INCLUDED diff --git a/composer/PdClasses.cpp b/composer/PdClasses.cpp new file mode 100644 index 0000000..d8ca17a --- /dev/null +++ b/composer/PdClasses.cpp @@ -0,0 +1,286 @@ +#include "PdClasses.hpp" +#include "Song.hpp" +#include "Track.hpp" +#include "Pattern.hpp" + +#include + +using std::cout; +using std::cerr; +using std::endl; + +#define IS_A_FLOAT(atom,index) ((atom+index)->a_type == A_FLOAT) + +t_atom result_argv[MAX_RESULT_SIZE]; +int result_argc; + +t_class *track_proxy_class; +t_class *song_proxy_class; + +void track_proxy_setup(void) +{ + track_proxy_class = class_new( + gensym("track"), + (t_newmethod)track_proxy_new, + (t_method)track_proxy_free, + sizeof(t_track_proxy), + CLASS_DEFAULT, + A_SYMBOL, A_SYMBOL, A_NULL + ); + class_addmethod(track_proxy_class, (t_method)track_proxy_getpatterns, \ + gensym("getpatterns"), A_NULL); + class_addmethod(track_proxy_class, (t_method)track_proxy_getpatternsize, \ + gensym("getpatternsize"), A_FLOAT, A_NULL); + class_addmethod(track_proxy_class, (t_method)track_proxy_setrow, \ + gensym("setrow"), A_GIMME, A_NULL); + class_addmethod(track_proxy_class, (t_method)track_proxy_getrow, \ + gensym("getrow"), A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(track_proxy_class, (t_method)track_proxy_addpattern, \ + gensym("addpattern"), A_SYMBOL, A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(track_proxy_class, (t_method)track_proxy_removepattern, \ + gensym("removepattern"), A_FLOAT, A_NULL); + class_addmethod(track_proxy_class, (t_method)track_proxy_resizepattern, \ + gensym("resizepattern"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL); + class_addmethod(track_proxy_class, (t_method)track_proxy_copypattern, \ + gensym("copypattern"), A_SYMBOL, A_SYMBOL, A_NULL); + /* class_addmethod(track_proxy_class, (t_method)track_proxy_data, \ + gensym("data"), A_GIMME, A_NULL);*/ +#if PD_MINOR_VERSION >= 37 + //class_setpropertiesfn(track_proxy_class, track_proxy_properties); + class_setsavefn(track_proxy_class, track_proxy_save); +#endif + class_sethelpsymbol(track_proxy_class, gensym("track.pd")); +} + +static t_track_proxy *track_proxy_new(t_symbol *song_name, t_symbol *track_name) +{ + t_track_proxy *x = (t_track_proxy*)pd_new(track_proxy_class); + x->outlet = outlet_new(&x->x_obj, &s_list); + x->editor_open = 0; + + // get or create Track object: + x->track = Track::byName(song_name->s_name, track_name->s_name); + + // set send/recv for communication with editor + Song *song = x->track->getSong(); + string base_name = "track_proxy-" + song->getName() + "-" + x->track->getName(); + string recv_name = base_name + "-r"; + string send_name = base_name + "-s"; + x->editor_recv = gensym(recv_name.c_str()); + x->editor_send = gensym(send_name.c_str()); + pd_bind(&x->x_obj.ob_pd, x->editor_recv); + + // bind to TRACK_SELECTOR for loading in-patch data + pd_bind(&x->x_obj.ob_pd, gensym(TRACK_SELECTOR)); + + return x; +} + +static void track_proxy_free(t_track_proxy *x) +{ + pd_unbind(&x->x_obj.ob_pd, gensym(TRACK_SELECTOR)); + /* LATER find a way to get TRACK_SELECTOR unbound earlier (at end of load?) */ + t_pd* x2; + while((x2 = pd_findbyclass(gensym(TRACK_SELECTOR), track_proxy_class))) + pd_unbind(x2, gensym(TRACK_SELECTOR)); + + pd_unbind(&x->x_obj.ob_pd, x->editor_recv); +} + +static void track_proxy_save(t_gobj *z, t_binbuf *b) +{ + t_track_proxy *x = (t_track_proxy*)z; + Track *t = x->track; + Song *s = t->getSong(); + + binbuf_addv(b, "ssiisss;", gensym("#X"), gensym("obj"), + (t_int)x->x_obj.te_xpix, (t_int)x->x_obj.te_ypix, + gensym("track"), gensym(s->getName().c_str()), + gensym(t->getName().c_str())); + + for(unsigned int p = 0; p < t->getPatternCount(); p++) + { + binbuf_addv(b, "ss", gensym(TRACK_SELECTOR), gensym("data")); + Pattern *pattern = t->getPattern(p); + t_int r = pattern->getRows(); + t_int c = pattern->getColumns(); + binbuf_addv(b, "siii", gensym(pattern->getName().c_str()), p, r, c); + t_atom tmp; + for(unsigned int j = 0; j < r; j++) + { + for(unsigned int k = 0; k < c; k++) + { + tmp = pattern->getCell(j, k); + switch(tmp.a_type) + { + case A_SYMBOL: + binbuf_addv(b, "s", tmp.a_w.w_symbol); + break; + case A_FLOAT: + binbuf_addv(b, "f", tmp.a_w.w_float); + break; + default: + binbuf_addv(b, "s", gensym("?")); + break; + } + } + } + binbuf_addv(b, ";"); + } + + binbuf_addv(b, "sss;", gensym(TRACK_SELECTOR), gensym("data"), gensym("end")); +} + +static void track_proxy_send_result(t_track_proxy *x, int outlet, int editor) +{ + if(result_argc <= 0) return; + if(outlet) + { + outlet_list(x->outlet, &s_list, result_argc, &result_argv[0]); + } + if(editor) + { + } +} + +static int track_proxy_getpatterns(t_track_proxy *x) +{ + SETSYMBOL(&result_argv[0], gensym("patternnames")); + result_argc = 1; + for(unsigned int i = 0; i < x->track->getPatternCount(); i++) + { + if(result_argc >= MAX_RESULT_SIZE) + { + pd_error(x, "getpatternnames: result too long"); + return -2; + } + Pattern *pattern = x->track->getPattern(i); + if(!pattern) + { + pd_error(x, "getpatternnames: no such pattern: %d", i); + return -1; + } + SETSYMBOL(&result_argv[result_argc], gensym(pattern->getName().c_str())); + result_argc++; + } + return 0; +} + +static int track_proxy_getpatternsize(t_track_proxy *x, t_floatarg pat) +{ + t_int p = (t_int) pat; + Pattern *pattern = x->track->getPattern(p); + if(!pattern) + { + pd_error(x, "getpatternsize: no such pattern: %d", p); + return -1; + } + SETSYMBOL(&result_argv[0], gensym("patternsize")); + SETFLOAT(&result_argv[1], (t_float) p); + SETFLOAT(&result_argv[2], pattern->getRows()); + SETFLOAT(&result_argv[3], pattern->getColumns()); + result_argc = 4; + return 0; +} + +static int track_proxy_setrow(t_track_proxy *x, t_symbol *sel, int argc, t_atom *argv) +{ + if(argc < 2 || !IS_A_FLOAT(argv,0) || !IS_A_FLOAT(argv,1)) + { + pd_error(x, "setrow: usage: setrow ..."); + return -1; + } + t_int p = (t_int) argv[0].a_w.w_float; + t_int r = (t_int) argv[1].a_w.w_float; + Pattern *pattern = x->track->getPattern(p); + if(!pattern) + { + pd_error(x, "setrow: no such pattern: %d", p); + return -2; + } + if((argc - 2) != pattern->getColumns()) + { + pd_error(x, "setrow: input error: must provide exactly %d elements for a row", pattern->getColumns()); + return -3; + } + for(unsigned int i = 2; i < argc; i++) + { + pattern->setCell(r, i - 2, argv[i]); + } + result_argc = 0; + return 0; +} + +static int track_proxy_getrow(t_track_proxy *x, t_floatarg pat, t_floatarg rownum) +{ + t_int p = (t_int) pat; + t_int r = (t_int) rownum; + Pattern *pattern = x->track->getPattern(p); + if(!pattern) + { + pd_error(x, "getrow: no such pattern: %d", p); + return -2; + } + SETSYMBOL(&result_argv[0], gensym("patternrow")); + SETFLOAT(&result_argv[1], (t_float) p); + SETFLOAT(&result_argv[2], (t_float) r); + result_argc = 3; + for(unsigned int i = 0; i < pattern->getColumns(); i++) + { + if(result_argc >= MAX_RESULT_SIZE) + { + pd_error(x, "getrow: result too long"); + return -2; + } + result_argv[result_argc] = pattern->getCell(r, i); + result_argc++; + } + return 0; +} + +static int track_proxy_addpattern(t_track_proxy *x, t_symbol *name, t_floatarg rows, t_floatarg cols) +{ + t_int r = (t_int) rows; + t_int c = (t_int) cols; + x->track->addPattern(r, c, string(name->s_name)); + return 0; +} + +static int track_proxy_removepattern(t_track_proxy *x, t_floatarg pat) +{ + t_int p = (t_int) pat; + Pattern *pattern = x->track->getPattern(p); + if(!pattern) + { + pd_error(x, "removepattern: no such pattern: %d", p); + return -2; + } + pd_error(x, "removepattern: not implemented yet"); + return -9; +} + +static int track_proxy_resizepattern(t_track_proxy *x, t_floatarg pat, t_floatarg rows, t_floatarg cols) +{ + t_int p = (t_int) pat; + t_int r = (t_int) rows; + t_int c = (t_int) cols; + Pattern *pattern = x->track->getPattern(p); + if(!pattern) + { + pd_error(x, "resizepattern: no such pattern: %d", p); + return -2; + } + pattern->resize(r, c); + return 0; +} + +static int track_proxy_copypattern(t_track_proxy *x, t_symbol *src, t_symbol *dst) +{ + pd_error(x, "copypattern: not implemented yet"); + return -9; +} + +void composer_setup() +{ + track_proxy_setup(); +} diff --git a/composer/PdClasses.hpp b/composer/PdClasses.hpp new file mode 100644 index 0000000..acf261e --- /dev/null +++ b/composer/PdClasses.hpp @@ -0,0 +1,40 @@ +#ifndef COMPOSER_PDCLASSES_H_INCLUDED +#define COMPOSER_PDCLASSES_H_INCLUDED + +#include + +#define MAX_RESULT_SIZE 128 + +#define TRACK_SELECTOR "#composer::track" +#define SONG_SELECTOR "#composer::song" + +class Track; +class Song; + +typedef struct _track_proxy +{ + t_object x_obj; + t_outlet *outlet; + Track *track; + t_int editor_open; + t_symbol *editor_recv; + t_symbol *editor_send; +} t_track_proxy; + +void track_proxy_setup(void); +static t_track_proxy *track_proxy_new(t_symbol *song_name, t_symbol *track_name); +static void track_proxy_free(t_track_proxy *x); +static void track_proxy_save(t_gobj *z, t_binbuf *b); +static void track_proxy_send_result(t_track_proxy *x, int outlet, int editor); +static int track_proxy_getpatterns(t_track_proxy *x); +static int track_proxy_getpatternsize(t_track_proxy *x, t_floatarg pat); +static int track_proxy_setrow(t_track_proxy *x, t_symbol *sel, int argc, t_atom *argv); +static int track_proxy_getrow(t_track_proxy *x, t_floatarg pat, t_floatarg rownum); +static int track_proxy_addpattern(t_track_proxy *x, t_symbol *name, t_floatarg rows, t_floatarg cols); +static int track_proxy_removepattern(t_track_proxy *x, t_floatarg pat); +static int track_proxy_resizepattern(t_track_proxy *x, t_floatarg pat, t_floatarg rows, t_floatarg cols); +static int track_proxy_copypattern(t_track_proxy *x, t_symbol *src, t_symbol *dst); + +extern "C" void composer_setup(void); + +#endif // COMPOSER_PDCLASSES_H_INCLUDED diff --git a/composer/Song.cpp b/composer/Song.cpp new file mode 100644 index 0000000..c793504 --- /dev/null +++ b/composer/Song.cpp @@ -0,0 +1,42 @@ +#include "Song.hpp" + +#include + +using std::cout; +using std::cerr; +using std::endl; + +map Song::byname; + +Song::Song(string songName) +: name(songName) +{ +} + +Song *Song::byName(string songName) +{ + if(byname.find(songName) == byname.end()) + byname[songName] = new Song(songName); + + return byname[songName]; +} + +void Song::print() +{ + cerr << "---- Song: " << name << " ----" << endl; + + for(map::iterator i = tracks.begin(); i != tracks.end(); i++) + { + cerr << " Track[" << i->first << "]: " << i->first << endl; + } + + cerr << "---- End song (" << name << ") ----" << endl; +} + +Track *Song::getTrackByName(string trackName) +{ + if(tracks.find(trackName) == tracks.end()) + return 0; + else + return tracks[trackName]; +} diff --git a/composer/Song.hpp b/composer/Song.hpp new file mode 100644 index 0000000..ead7285 --- /dev/null +++ b/composer/Song.hpp @@ -0,0 +1,31 @@ +#ifndef COMPOSER_SONG_H_INCLUDED +#define COMPOSER_SONG_H_INCLUDED + +#include +#include + +#include + +#include "Track.hpp" + +using std::map; +using std::string; + +class Song +{ +private: + static map byname; +public: + static Song *byName(string songName); +private: + string name; + map tracks; +protected: + Song(string songName); +public: + void print(); + Track *getTrackByName(string trackName); + inline const string &getName() {return name;} +}; + +#endif // COMPOSER_SONG_H_INCLUDED diff --git a/composer/TODO b/composer/TODO deleted file mode 100644 index 9ccc4ae..0000000 --- a/composer/TODO +++ /dev/null @@ -1,4 +0,0 @@ -TODO: - - optimize performance of symbol->index lookups, especially for patterns - - check for memory leaks - - compress in-patch data diff --git a/composer/Track.cpp b/composer/Track.cpp new file mode 100644 index 0000000..47ad81b --- /dev/null +++ b/composer/Track.cpp @@ -0,0 +1,47 @@ +#include "Song.hpp" +#include "Track.hpp" +#include "Pattern.hpp" + +#include + +using std::cout; +using std::cerr; +using std::endl; + +Track::Track(Song *_song, string trackName) +: name(trackName), song(_song) +{ +} + +Track *Track::byName(string songName, string trackName) +{ + Song *song = Song::byName(songName); + + Track *track = song->getTrackByName(trackName); + if(!track) track = new Track(song, trackName); + + return track; +} + +void Track::print() +{ + cerr << "---- Track: " << name << " ----" << endl; + + for(unsigned int i = 0; i < patterns.size(); i++) + { + cerr << " Pattern[" << patterns[i]->getName() << "]: " << patterns[i]->getName() << endl; + } + + cerr << "---- End track (" << name << ") ----" << endl; +} + +void Track::addPattern(int rows, int cols, string name) +{ + Pattern *pattern = new Pattern(rows, cols, name); + patterns.push_back(pattern); +} + +Pattern *Track::getPattern(int n) +{ + return patterns[n]; +} diff --git a/composer/Track.hpp b/composer/Track.hpp new file mode 100644 index 0000000..3bd2135 --- /dev/null +++ b/composer/Track.hpp @@ -0,0 +1,34 @@ +#ifndef COMPOSER_TRACK_H_INCLUDED +#define COMPOSER_TRACK_H_INCLUDED + +#include +#include + +#include + +using std::string; +using std::vector; + +class Song; +class Pattern; + +class Track +{ +public: + static Track *byName(string songName, string trackName); +private: + string name; + vector patterns; + Song *song; +protected: + Track(Song *_song, string trackName); +public: + void print(); + void addPattern(int rows, int cols, string name); + Pattern *getPattern(int n); + inline unsigned int getPatternCount() {return patterns.size();} + inline Song *getSong() {return song;} + inline const string &getName() {return name;} +}; + +#endif // COMPOSER_TRACK_H_INCLUDED diff --git a/composer/arraylist.h b/composer/arraylist.h deleted file mode 100644 index b625379..0000000 --- a/composer/arraylist.h +++ /dev/null @@ -1,118 +0,0 @@ -/* ------------------------------------------------------------------------ */ -/* Copyright (c) 2009 Federico Ferri. */ -/* For information on usage and redistribution, and for a DISCLAIMER OF ALL */ -/* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ -/* */ -/* arraylist.h: macro library for dynamic arrays */ -/* */ -/* This program 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. */ -/* */ -/* See file LICENSE for further informations on licensing terms. */ -/* */ -/* This program 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 this program; if not, write to the Free Software Foundation, */ -/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* ------------------------------------------------------------------------ */ - -#include "common.h" - -#ifndef __ARRAYLIST_H_INCLUDED_ -#define __ARRAYLIST_H_INCLUDED_ - -#define ArrayListDeclare(name, type, sizetype) \ - type* name; \ - sizetype name ## _maxsize; \ - sizetype name ## _count - -#define ArrayListDeclareWithPrefix(prefix, name, type, sizetype) \ - prefix type* name; \ - prefix sizetype name ## _maxsize; \ - prefix sizetype name ## _count - -#define ArrayListInit(arrName, type, initSize) \ - arrName ## _maxsize = initSize; \ - if(initSize > 0) arrName = (type*)getbytes(sizeof(type) * (initSize)); \ - else arrName = NULL; \ - arrName ## _count = 0 - -#define ArrayListAdd(arrName, type, objToAdd) \ - if(arrName ## _count >= arrName ## _maxsize) { \ - arrName = (type*)resizebytes(arrName, arrName ## _maxsize, (arrName ## _maxsize)*2); \ - }; \ - arrName[ arrName ## _count ++ ] = (type) objToAdd; \ - -#define ArrayListRemove(arrName, objToRem) \ - { \ - int i,j; \ - for(i=0; i< arrName ## _count; i++) \ - if(arrName[i] == objToRem) { \ - for(j=i; j< arrName ## _count - 1; j++) { \ - arrName[j] = arrName[j+1]; \ - } \ - arrName[ arrName ## _count -- ] = 0L; \ - break; \ - } \ - } - -#define ArrayListRemoveByIndex(arrName, index) \ - { \ - int i,j; \ - for(i=0; i< arrName ## _count; i++) \ - if(i == index) { \ - for(j=i; j< arrName ## _count - 1; j++) { \ - arrName[j] = arrName[j+1]; \ - } \ - arrName[ arrName ## _count -- ] = 0L; \ - break; \ - } \ - } - -#define ArrayListRemoveByName(arrName, name) \ - { \ - int i,j; \ - for(i=0; i< arrName ## _count; i++) \ - if(arrName[i] && arrName[i]->x_name == name) { \ - for(j=i; j< arrName ## _count - 1; j++) { \ - arrName[j] = arrName[j+1]; \ - } \ - arrName[ arrName ## _count -- ] = 0L; \ - break; \ - } \ - } - -#define ArrayListGetByName(arrName, n, type, result) \ - type result = (type) 0L; \ - if(arrName) { \ - int i; \ - for(i=0; i< arrName ## _count; i++) { \ - if(arrName[i] && arrName[i]->x_name == n) { \ - result = arrName[i]; break; \ - } \ - } \ - } - -#define ArrayListGetIndexByName(arrName, n, type, result) \ - type result = (type) -1; \ - if(arrName) { \ - int i; \ - for(i=0; i< arrName ## _count; i++) { \ - if(arrName[i] && arrName[i]->x_name == n) { \ - result = i; \ - break; \ - } \ - } \ - } - -#define ArrayListFree(arrName, type) \ - freebytes(arrName, arrName ## _maxsize * sizeof(type)) - -#endif // __ARRAYLIST_H_INCLUDED_ diff --git a/composer/common.h b/composer/common.h deleted file mode 100644 index 1dc78c0..0000000 --- a/composer/common.h +++ /dev/null @@ -1,199 +0,0 @@ -/* ------------------------------------------------------------------------ */ -/* Copyright (c) 2009 Federico Ferri. */ -/* For information on usage and redistribution, and for a DISCLAIMER OF ALL */ -/* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ -/* */ -/* composer: a music composition framework for pure-data */ -/* */ -/* This program 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. */ -/* */ -/* See file LICENSE for further informations on licensing terms. */ -/* */ -/* This program 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 this program; if not, write to the Free Software Foundation, */ -/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* ------------------------------------------------------------------------ */ - -#ifndef COMPOSER_COMMON_H_INCLUDED -#define COMPOSER_COMMON_H_INCLUDED - -#include -#include -#include -#include "m_pd.h" -#include "m_imp.h" -#include "g_canvas.h" -#include "s_stuff.h" -#include "t_tk.h" -#include -#include -#include "arraylist.h" - -#define PTR "0x%lx" -#ifdef DEBUG -#define debugprint(args...) post( args ) -#define DEBUG_BOOL 1 -#else -#define debugprint(args...) -#define DEBUG_BOOL 0 -#endif - -#define STRINGIFY(x) #x - -#define WRAP(v, w) (((v) < 0 ? (1+(int)((-(v))/(w)))*(w) : (v)) % w) - -#define TRACK_SELECTOR "#TRACK" -#define SONG_SELECTOR "#SONG" - -static void list_snconvf(char *buf, size_t bufsz, t_symbol* s, size_t argc, t_atom* argv); - -struct _track; -struct _pattern; - -typedef struct _song -{ - t_symbol* x_name; - ArrayListDeclare(x_tracks, struct _track*, t_int); - struct _track* x_mastertrack; -} t_song; - -typedef struct _song_proxy -{ - t_object x_obj; - t_outlet* outlet; - t_song* x_song; - t_int b_editor_open; - t_symbol* rcv; -} t_song_proxy; - -typedef struct _track -{ - t_symbol* x_name; - t_song* x_song; - t_int x_ncolumns; - t_outlet* outlet; - ArrayListDeclare(x_patterns, struct _pattern*, t_int); - t_float x_currentpat; -} t_track; - -typedef struct _track_proxy -{ - t_object x_obj; - t_outlet* outlet; - t_track* x_track; - t_int b_editor_open; - t_symbol* rcv; -} t_track_proxy; - -typedef struct _pattern -{ - t_symbol* x_name; - t_track* x_track; - ArrayListDeclare(x_rows, t_atom*, t_int); -} t_pattern; - -static t_song* song_new(t_symbol* song_name); -static void song_mastertrack_fix_cols(t_song* x); -static void song_free(t_song* x); -static void song_internal_resize_cols(t_song* x, t_int sz); -static t_song* song_get(t_symbol* song_name); -static int song_exists(t_symbol* song_name); -static void song_loaddata(t_song* x, int argc, t_atom* argv); -static void song_binbuf_save(t_song* t, t_symbol* selector, t_binbuf* b); - -static t_track* track_new(t_symbol* song_name, t_symbol* track_name, t_int columns); -static t_track* mastertrack_new(t_song* song, t_symbol* track_name, t_int columns); -static t_track* song_create_track(t_song* x, t_symbol* track_name, t_int columns); -static void track_free(t_track* x); -static t_track* track_get(t_symbol* song_name, t_symbol* track_name); -static int track_exists(t_symbol* song_name, t_symbol* track_name); -static void track_binbuf_save(t_track* x, t_symbol* selector, t_binbuf* b); - - -static t_pattern* pattern_new(t_track* track, t_symbol* name, t_int rows); -static t_pattern* pattern_clone(t_pattern* src, t_symbol* newname); -static void pattern_free(t_pattern* x); -static void pattern_rename(t_pattern* x, t_symbol* newname); -static void pattern_resize(t_pattern *x, t_int newsize); -static void pattern_resize_cols(t_pattern* x, t_int newcols); -static void pattern_init_cell(t_atom* a); -static void pattern_new_empty_row(t_pattern* x); -static t_atom* pattern_getrow(t_pattern* x, t_int row); -static t_atom* pattern_clone_row(t_pattern* x, t_atom* row); -static t_atom* pattern_getcell(t_pattern* x, t_int row, t_int col); -static void pattern_setrow(t_pattern* x, t_int row, t_atom* rowdata); -static void pattern_setcell(t_pattern* x, t_int row, t_int col, t_atom* a); -static t_pattern* pattern_get(t_symbol* song_name, t_symbol* track_name, t_symbol* pattern_name); -static int pattern_exists(t_symbol* song_name, t_symbol* track_name, t_symbol* pattern_name); - -void song_proxy_setup(void); -static t_song_proxy* song_proxy_new(t_symbol* song_name); -static void song_proxy_free(t_song_proxy* x); -static t_atom* song_proxy_get_pattern_names(t_song_proxy* x); -static void song_proxy_float(t_song_proxy* x, t_floatarg f); -static void song_proxy_properties(t_gobj* z, t_glist* owner); -static void song_proxy_properties_close(t_gobj* z, t_glist* owner); -static void song_proxy_save(t_gobj* z, t_binbuf* b); -static t_atom* song_proxy_gettracks(t_song_proxy* x); -static void song_proxy_gettracks_o(t_song_proxy* x); -static t_int song_proxy_gettracks_count(t_song_proxy* x); -static void song_proxy_gettracks_count_o(t_song_proxy* x); -static void song_proxy_anything(t_song_proxy* x, t_symbol* s, int argc, t_atom* argv); -static void song_proxy_loadsonginfo(t_song_proxy* x, t_symbol* s, int argc, t_atom* argv); -static void song_proxy_loaddata(t_song_proxy* x, t_symbol* s, int argc, t_atom* argv); -static t_atom* song_proxy_getpatternlength(t_song_proxy* x, t_symbol* pat_name); -static void song_proxy_editcmd(t_song_proxy* x, t_symbol* s_, int argc, t_atom* argv_); -static void song_proxy_sendgui(t_song_proxy* x, t_symbol* s, int argc, t_atom* argv); -static void song_proxy_setrow(t_song_proxy* x, t_symbol* sel, int argc, t_atom* argv); -static t_atom* song_proxy_getrow(t_song_proxy* x, t_symbol* pat_name, t_floatarg rownum); -static t_atom* song_proxy_getrow_with_header(t_song_proxy* x, t_symbol* pat_name, t_floatarg rownum); -static void song_proxy_getrow_o(t_song_proxy* x, t_symbol* pat_name, t_floatarg rownum); -static void song_proxy_setcell(t_song_proxy* x, t_symbol* sel, int argc, t_atom* argv); -static t_atom* song_proxy_getcell(t_song_proxy* x, t_symbol* pat_name, t_floatarg rownum, t_floatarg colnum); -static t_atom* song_proxy_getcell_with_header(t_song_proxy* x, t_symbol* pat_name, t_floatarg rownum, t_floatarg colnum); -static void song_proxy_getcell_o(t_song_proxy* x, t_symbol* pat_name, t_floatarg rownum, t_floatarg colnum); -static t_pattern* song_proxy_resizepattern(t_song_proxy* x, t_symbol* name, t_floatarg rows); - -void track_proxy_setup(void); -static t_track_proxy* track_proxy_new(t_symbol* song_name, t_symbol* track_name, t_floatarg cols); -static void track_proxy_free(t_track_proxy* x); -static void track_proxy_reload(t_track_proxy* x); -static void track_proxy_properties(t_gobj* z, t_glist* owner); -static void track_proxy_properties_close(t_gobj* z, t_glist* owner); -static void track_proxy_save(t_gobj* z, t_binbuf* b); -static void track_proxy_sendrow(t_track_proxy* x, t_pattern* pat, t_int row); -static void track_proxy_anything(t_track_proxy* x, t_symbol* s, int argc, t_atom* argv); -static void track_proxy_loaddata(t_track_proxy* x, t_symbol* s, int argc, t_atom* argv); -static t_atom* track_proxy_getpatternlength(t_track_proxy* x, t_symbol* pat_name); -static void track_proxy_editcmd(t_track_proxy* x, t_symbol* s, int argc, t_atom* argv); -static void track_proxy_sendgui(t_track_proxy* x, t_symbol* s, int argc, t_atom* argv); -static void track_proxy_float(t_track_proxy* x, t_floatarg f); -static void track_proxy_setrow(t_track_proxy* x, t_symbol* sel, int argc, t_atom* argv); -static t_atom* track_proxy_getrow(t_track_proxy* x, t_symbol* pat_name, t_floatarg rownum); -static t_atom* track_proxy_getrow_with_header(t_track_proxy* x, t_symbol* pat_name, t_floatarg rownum); -static void track_proxy_getrow_o(t_track_proxy* x, t_symbol* pat_name, t_floatarg rownum); -static void track_proxy_setcell(t_track_proxy* x, t_symbol* sel, int argc, t_atom* argv); -static t_atom* track_proxy_getcell(t_track_proxy* x, t_symbol* pat_name, t_floatarg rownum, t_floatarg colnum); -static t_atom* track_proxy_getcell_with_header(t_track_proxy* x, t_symbol* pat_name, t_floatarg rownum, t_floatarg colnum); -static void track_proxy_getcell_o(t_track_proxy* x, t_symbol* pat_name, t_floatarg rownum, t_floatarg colnum); -static t_pattern* track_proxy_addpattern(t_track_proxy* x, t_symbol* name, t_floatarg rows); -static int track_proxy_removepattern(t_track_proxy* x, t_symbol* name); -static t_pattern* track_proxy_resizepattern(t_track_proxy* x, t_symbol* name, t_floatarg rows); -static t_pattern* track_proxy_renamepattern(t_track_proxy* x, t_symbol* name, t_symbol* newname); -static t_pattern* track_proxy_copypattern(t_track_proxy* x, t_symbol* src, t_symbol* dst); - -ArrayListDeclareWithPrefix(extern, songs, t_song*, int); - -void composer_setup(void); - -#endif // COMPOSER_COMMON_H_INCLUDED diff --git a/composer/composer.c b/composer/composer.c deleted file mode 100644 index 6d86758..0000000 --- a/composer/composer.c +++ /dev/null @@ -1,91 +0,0 @@ -/* ------------------------------------------------------------------------ */ -/* Copyright (c) 2009 Federico Ferri. */ -/* For information on usage and redistribution, and for a DISCLAIMER OF ALL */ -/* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ -/* */ -/* composer: a music composition framework for pure-data */ -/* */ -/* This program 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. */ -/* */ -/* See file LICENSE for further informations on licensing terms. */ -/* */ -/* This program 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 this program; if not, write to the Free Software Foundation, */ -/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* ------------------------------------------------------------------------ */ - -#include "common.h" - -#include "song.c" -#include "track.c" -#include "pattern.c" -#include "song_proxy.c" -#include "track_proxy.c" - -ArrayListDeclare(songs, t_song*, int); - -void list_snconvf(char *buf, size_t bufsz, t_symbol* s, size_t argc, t_atom* argv) { - static const unsigned int tmpsz = 80; - char* tmp; - size_t i,j,len; - if(bufsz < 1) goto list_snconvf_szbug; - buf[0] = '\0'; - len = 0; - if(s != gensym("")) { - len += strlen(s->s_name) + 1; - if(bufsz <= len) goto list_snconvf_szbug; - strncat(buf, s->s_name, bufsz); - strncat(buf, " ", bufsz); - } - for(i = 0; i < argc; i++) { - if(i > 0) { - len += 1; - if(bufsz <= len) goto list_snconvf_szbug; - strncat(buf, " ", bufsz); - } - if(argv[i].a_type == A_FLOAT) { - tmp = (char*)getbytes(tmpsz*sizeof(char)); - if(argv[i].a_w.w_float == (t_float)(t_int)argv[i].a_w.w_float) - sprintf(tmp, "%ld", (t_int)argv[i].a_w.w_float); - else - sprintf(tmp, "%f", argv[i].a_w.w_float); - len += strlen(tmp); - if(bufsz <= len) goto list_snconvf_szbug; - strncat(buf, tmp, bufsz); - freebytes(tmp, tmpsz*sizeof(char)); - } else if(argv[i].a_type == A_SYMBOL) { - len += strlen(argv[i].a_w.w_symbol->s_name); - if(bufsz <= len) goto list_snconvf_szbug; - strncat(buf, argv[i].a_w.w_symbol->s_name, bufsz); - } else { - len += 4; - if(bufsz <= len) goto list_snconvf_szbug; - strncat(buf, "null", bufsz); - } - } - if(strlen(buf) >= bufsz) { - goto list_snconvf_szbug; - } - return; - -list_snconvf_szbug: - debugprint("track: BUG: list_snconvf_szbug (message too long)"); - bug("track: BUG: list_snconvf_szbug (message too long)"); -} - -void composer_setup(void) { - debugprint("loading composer library for pd"); - sys_vgui("source {window.tk}\n"); - song_proxy_setup(); - track_proxy_setup(); -} diff --git a/composer/editor.tk b/composer/editor.tk new file mode 100644 index 0000000..1b90732 --- /dev/null +++ b/composer/editor.tk @@ -0,0 +1,614 @@ +# ------------------------------------------------------------------------ +# Copyright (c) 2009 Federico Ferri. +# For information on usage and redistribution, and for a DISCLAIMER OF ALL +# WARRANTIES, see the file, "LICENSE.txt," in this distribution. +# +# composer: a music composition framework for pure-data +# +# This program 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. +# +# See file LICENSE for further informations on licensing terms. +# +# This program 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 this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# Based on PureData by Miller Puckette and others. +# ------------------------------------------------------------------------ + +package require Tcl 8.5 +package require Tk 8.5 +package require Tktable 2.9 + +namespace eval pd::composer { + variable debug + variable w + array set w {} + variable songname + array set songname {} + variable trackname + array set trackname {} + variable currentpattern + array set currentpattern {} + variable length + array set length {} + variable columns + array set columns {} + variable patterns + array set patterns {} + variable tracks + array set tracks {} + + variable quirks_fix_int_floats 0 + variable symbolmap {empty {}} + # set to 1 until startup, for getting soon a pattern list + # affects the behavior of dispatcher::patterns branch + variable startup + array set startup {} + variable showpattern + array set showpattern {} + + proc debugPrint {args} { + variable debug + if {![info exists debug]} {set debug 0} + if {$debug} {puts stderr "composer-TCL: $args"} + } + + proc sendGui {what} { + debugPrint "sendGui $what" + catch {netsend $what} + lappend what \;\n + catch {pdsend $what} + catch {pd {*}$what} + } + + proc createPattern {id name len} { + debugPrint [info level 0] + variable length + variable patterns + + if {$name in $patterns($id)} { + return -code error "Pattern '$name' already exists" + } + set len [expr {int($len)}] + if {$len <= 0} { + return -code error "Length must be positive integer" + } + + sendGui [concat $id EDIT addpattern $name $len] + } + + proc removePattern {id name} { + debugPrint [info level 0] + variable length; + variable patterns; + + sendGui [concat $id EDIT removepattern $name] + } + + proc copyPattern {id src dst} { + debugPrint [info level 0] + variable length; + + sendGui [concat $id EDIT copypattern $src $dst] + } + + proc resizePattern {id name newSize} { + debugPrint [info level 0] + variable currentpattern; + variable length; + + if {$newSize == [dict get $length($id) $name]} return + + set len [expr {int($newSize)}] + if {$len <= 0} { + return -code error "Length must pe positive integer" + } + + sendGui [concat $id EDIT resizepattern $name $len] + } + + proc renamePattern {id name newName} { + debugPrint [info level 0] + variable length; + variable patterns; + + if {$name == $newName} return + if {$newName in $patterns($id)} { + return -code error "Pattern name '$newName' already exists" + } + set idx [lsearch -exact $patterns($id) $name] + if {$idx == -1} { + return -code error "No such pattern: '$name'" + } + + sendGui [concat $id EDIT renamepattern $name $newName] + } + + proc generateNewPatternName {id} { + debugPrint [info level 0] + variable patterns; + set n 0 + while 1 { + set t "P[format %.02d $n]" + if {$t in $patterns($id)} {incr n} else {return $t} + } + } + + proc displayPattern {id name} { + debugPrint "request-pattern-length" + variable showpattern + set showpattern($id) 1 + sendGui [concat $id EDIT getpatternlength $name] + } + + proc updateTitle {id} { + variable w + variable songname + variable trackname + variable currentpattern + set t "Song: $songname($id)" + if {$currentpattern($id) == "Arrangement"} { + append t " Arrangement" + } else { + append t " Track: $trackname($id)" + if {$currentpattern($id) != {}} { + append t " Pattern: $currentpattern($id)" + } + } + wm title $w($id) $t + } + + proc displayPattern_async {id name} { + debugPrint [info level 0] + variable currentpattern + variable patterns + variable length + variable columns + variable w + variable songname + variable trackname + variable [getDataVar $id] + + set currentpattern($id) $name + updateTitle $id + + if {$currentpattern($id) == {}} { + grid forget $w($id).t + return + } + + set rows [dict get $length($id) $name] + set cols $columns($id) + grid $w($id).t -row 10 -column 0 -sticky news + debugPrint "resizing tktable widget to ${rows}x${cols}" + $w($id).t configure -state normal -variable [getDataVar $id] -rows $rows -cols [expr {1+$cols}] + $w($id).f.p configure -values $patterns($id) + $w($id).f.p current [lsearch -exact $patterns($id) $name] + } + + proc displayCurrentPattern {id} { + debugPrint [info level 0] + variable currentpattern + variable w + debugPrint "current pattern is {$currentpattern($id)}" + displayPattern $id $currentpattern($id) + } + + proc rowTag {id r} { + if {$r % $::div1 == 0} {return "alt0"} + if {$r % $::div2 == 0} {return "alt1"} + } + + proc refreshGrid {id} { + debugPrint [info level 0] + variable currentpattern + debugPrint "currentPattern is {$currentpattern($id)}" + variable w + $w($id).t configure -padx [$w($id).t cget -padx] + } + + proc edit {id r c bwrite value} { + # NOT USED + #if {$bwrite} { + # sendGui [concat $id EDIT setcell $currentpattern($id) $r $c $value] + #} else { + #} + } + + proc getDataVar {id {P {}}} { + variable currentpattern + variable songname + variable trackname + if {$P == ""} {set P $currentpattern($id)} + set n "[namespace current]::data_$songname($id)_$trackname($id)_$P" + if {![info exists $n]} {array set $n {}} + return $n + } + + proc createMainWindow {id} { + debugPrint [info level 0] + variable currentpattern; + variable w + variable songname + variable trackname + variable patterns + variable startup + variable showpattern + variable [getDataVar $id] + + catch {destroy $w($id)} + debugPrint "creating window with path = '$w($id)'" + toplevel $w($id) + + debugPrint "top-toolbar(frame)" + grid [ttk::frame $w($id).f] \ + -row 5 -columnspan 2 -sticky news + debugPrint "label" + grid [ttk::label $w($id).f.l -text "Pattern: "] \ + -row 0 -column 0 -in $w($id).f + debugPrint "combobox patterns" + grid [ttk::combobox $w($id).f.p -textvariable "[namespace current]::currentpattern($id)"] \ + -row 0 -column 1 -in $w($id).f + debugPrint "divs" + grid [ttk::label $w($id).f.ld1 -text "Div1: "] \ + -row 0 -column 2 -in $w($id).f + grid [spinbox $w($id).f.d1 -command "[namespace current]::refreshGrid $id" -from 8 -to 64 \ + -increment 1 -format %3.0f -width 3 -textvar ::div1] \ + -row 0 -column 3 -in $w($id).f + grid [ttk::label $w($id).f.ld2 -text "Div2: "] \ + -row 0 -column 4 -in $w($id).f + grid [spinbox $w($id).f.d2 -command "[namespace current]::refreshGrid $id" -from 2 -to 64 \ + -increment 1 -format %3.0f -width 3 -textvar ::div2] \ + -row 0 -column 5 -in $w($id).f + + debugPrint "step2" + $w($id).f.p state readonly + + debugPrint "bindevent" + bind $w($id).f.p <> "[namespace current]::displayCurrentPattern $id" + debugPrint "table" + + table $w($id).t -state disabled \ + -insertofftime 0 \ + -bordercursor sb_h_double_arrow \ + -colorigin -1 -sparsearray 1 \ + -relief ridge -takefocus 1 -borderwidth 1 -colwidth 4 \ + -browsecmd "[namespace current]::activeCellChanges $id %r %c" \ + -cols 0 -rows 0 \ + -cache 0 \ + -usecommand 0 -command "[namespace current]::edit $id %r %c %i %s" \ + -colstretchmode none -rowstretchmode none \ + -flashmode 1 -flashtime 2 -autoclear 1 \ + -justify left -multiline 0 -resizeborders col \ + -selectmode extended -selecttype cell \ + -titlecols 1 -titlerows 0 -validate 1 \ + -validatecommand "[namespace current]::validateCommand $id %r %c %s %S" \ + -variable [getDataVar $id] -exportselection 1 \ + -xscrollcommand "$w($id).hscroll set" \ + -yscrollcommand "$w($id).vscroll set" \ + -rowtagcommand "[namespace current]::rowTag $id" + #grid $w($id).t -row 10 -column 0 -sticky news + + debugPrint "scrollbars" + grid [ttk::scrollbar $w($id).vscroll -orient vertical -command "$w($id).t yview"] -row 10 -column 1 -sticky ns + grid [ttk::scrollbar $w($id).hscroll -orient horizontal -command "$w($id).t xview"] -row 15 -column 0 -sticky ew + #grid [ttk::sizegrip $w($id).resize] -row 15 -column 1 -sticky se + + grid [ttk::entry $w($id).eval] -row 20 -columnspan 2 -sticky ew + bind $w($id).eval "set cmd \[$w($id).eval get]; namespace eval [namespace current] \$cmd; $w($id).eval delete 0 end" + + debugPrint "grid" + grid columnconfigure $w($id) 0 -weight 1 + grid rowconfigure $w($id) 10 -weight 1 + + debugPrint "table-tags" + $w($id).t tag configure active -relief solid -background gray -foreground black + $w($id).t tag configure flash -background red -foreground white + $w($id).t tag configure sel -background blue -foreground white + $w($id).t tag configure title -background gray -foreground white -justify right + $w($id).t tag configure alt0 -background "#20a8b8" + $w($id).t tag configure alt1 -background "#0f7f9f" + $w($id).t tag configure notecol -background "#dddded" + + debugPrint "wm" + wm minsize $w($id) 300 150 + wm protocol $w($id) WM_DELETE_WINDOW "[namespace current]::sendGui {$id EDIT editor-close}" + + debugPrint "menu" + menu $w($id).m -tearoff 0 + $w($id).m add command -label "New pattern..." \ + -command "[namespace current]::newPatternDialog $id" + $w($id).m add command -label "Pattern properties..." \ + -command "[namespace current]::patternPropertiesDialog $id" + $w($id).m add command -label "Remove pattern..." \ + -command "[namespace current]::removePatternConfirm $id" + $w($id).m add command -label "Create copy..." \ + -command "[namespace current]::copyPatternDialog $id" + + menu $w($id).mb + $w($id) configure -menu $w($id).mb + menu $w($id).mb.tools -tearoff 0 + $w($id).mb.tools add command -label {Reload} \ + -command {uplevel 0 {source $argv0}} + $w($id).mb add cascade -label {Pattern} -menu $w($id).m + $w($id).mb add cascade -label {Utils} -menu $w($id).mb.tools + + debugPrint "more-bind-events" + bind $w($id).t "$w($id).t activate @%x,%y; tk_popup $w($id).m %X %Y" + bind $w($id).t "switchColumnType $id" + + set startup($id) 1 + set showpattern($id) 0 + debugPrint "request-patterns" + sendGui [concat $id EDIT getpatterns] + sendGui [concat $id EDIT gettracks] + + return $w($id) + } + + proc switchColumnType {id} { + debugPrint [info level 0] + variable w + global colType + set curcol [$w($id).t index active col] + set tag {} + if {![info exists colType(c$curcol)]} { + set colType(c$curcol) {notes} + set tag {notecol} + } elseif {$colType(c$curcol) == {notes}} { + unset colType(c$curcol) + } + + $w($id).t tag col $tag $curcol + #refreshGrid + } + + proc activeCellChanges {id row col} { + debugPrint [info level 0] + variable w + if {$col < 0} {$w($id).t activate $row,[incr col]} + } + + proc validateCommand {id row col curVal newVal} { + debugPrint [info level 0] + variable currentpattern + variable symbolmap + + debugPrint "BEFORE: newVal = '$newVal'" + set newVal [dict get [dict merge [list $newVal $newVal] [lreverse $symbolmap]] $newVal] + debugPrint "AFTER: newVal = '$newVal'" + + sendGui [concat $id EDIT setcell $currentpattern($id) $row $col $newVal] + + return 1 + } + + proc patternPropertiesDialog_common {id options} { + debugPrint [info level 0] + variable currentpattern + variable w + set bname 1 + set blength 1 + set old_name {} + catch {set old_name $currentpattern($id)} + set vname {} + set vlength {} + set action_cancel {destroy %w} + set action_ok $action_cancel + + set opts {vname vlength bname blength action_ok action_cancel} + foreach opt $opts { + catch {set $opt [dict get $options $opt]} + } + foreach {o v} $options { + if {$o ni $opts} { + return -code error "Invalid option: $o" + } + } + + set w_ $w($id).patternProps + catch {destroy $w_} + toplevel $w_ + + foreach v {action_ok action_cancel} { + set $v [string map [list %ns [namespace current] %id $id %w $w_ %old_name $old_name] [set $v]] + } + + grid [ttk::label $w_.lname -text "Name: "] -row 0 -column 0 + grid [ttk::label $w_.llength -text "Rows: "] -row 1 -column 0 + grid [ttk::entry $w_.ename] -row 0 -column 1 + grid [ttk::entry $w_.elength] -row 1 -column 1 + grid [ttk::frame $w_.b] -row 2 -columnspan 2 + grid [ttk::button $w_.b.ok -text Ok -command $action_ok] -row 0 -column 0 -in $w_.b + grid [ttk::button $w_.b.cancel -text Cancel -command $action_cancel] -row 0 -column 1 -in $w_.b + + $w_.ename insert 0 $vname + $w_.elength insert 0 $vlength + + if {!$bname} {$w_.ename configure -state disabled} + if {!$blength} {$w_.elength configure -state disabled} + } + + proc patternPropertiesDialog {id {options {}}} { + debugPrint [info level 0] + variable currentpattern; + variable length; + + dict set options action_ok { + %ns::resizePattern %id %old_name [%w.elength get] + %ns::renamePattern %id %old_name [%w.ename get] + destroy %w + } + dict set options vname $currentpattern($id) + dict set options vlength [dict get $length($id) $currentpattern($id)] + patternPropertiesDialog_common $id $options + } + + proc copyPatternDialog {id {options {}}} { + debugPrint [info level 0] + variable w; + variable length; + + dict set options blength 0 + dict set options vname [generateNewPatternName $id] + dict set options vlength [dict get $length($id) $currentpattern($id)] + dict set options action_ok { + %ns::copyPattern %id %old_name [%w.ename get] + destroy %w + } + patternPropertiesDialog_common $id $options + } + + proc removePatternConfirm {id} { + debugPrint [info level 0] + variable currentpattern; + if {[tk_messageBox \ + -type yesno -default no \ + -title "Question" \ + -icon question -message "Do you confirm pattern delete?" \ + -detail "The operation cannot be undone" \ + -parent $w] == {yes}} { + removePattern $id $currentpattern($id) + } + } + + proc newPatternDialog {id {options {}}} { + debugPrint [info level 0] + dict set options action_ok { + %ns::createPattern %id [%w.ename get] [%w.elength get] + destroy %w + } + dict set options vname [generateNewPatternName $id] + dict set options vlength 16 + patternPropertiesDialog_common $id $options + } + + #entrypoint + proc init {id song_name track_name cols set_current_pattern debug_flag} { + debugPrint [info level 0] + variable debug + set debug [expr {$debug_flag != 0}] + variable w + variable songname + variable trackname + variable length + variable currentpattern + variable columns + set w($id) .w_${song_name}_${track_name} + set songname($id) $song_name + set trackname($id) $track_name + if {$set_current_pattern == {NULL}} { + set currentpattern($id) {} + } else { + set currentpattern($id) $set_current_pattern + } + set length($id) {} + set columns($id) $cols + } + + proc openWindow {id} { + debugPrint [info level 0] + createMainWindow $id + } + + proc closeWindow {id} { + debugPrint [info level 0] + variable w + destroy $w($id) + } + + proc setCellValueUI {id pat r c v} { + upvar 0 [getDataVar $id $pat] data + variable symbolmap + set data($r,$c) [dict get [dict merge [list $v $v] $symbolmap] $v] + } + + proc dispatch {id args} { + debugPrint [info level 0] + variable w + variable patterns + variable length + variable currentpattern + variable startup + variable showpattern + variable columns + variable quirks_fix_int_floats + switch -exact [lindex $args 0] { + patterns { + # for track mode + set patterns($id) [lrange $args 1 end] + debugPrint "patterns <- $patterns($id)" + $w($id).f.p configure -values $patterns($id) + if {$startup($id)} { + set startup($id) 0 + if {[llength $patterns($id)] > 0} { + displayPattern $id [lindex $patterns($id) 0] + } + } + } + tracks { + # for song mode + set tracks($id) [lrange $args 1 end] + debugPrint "tracks <- $tracks($id)" + set cols [llength $tracks($id)] + #debugPrint "resizing tktable widget to ${cols} cols" + #$w($id).t configure -state normal -cols $cols + set columns($id) $cols + } + patternlength { + set pat_name [lindex $args 1] + set pat_length [lindex $args 2] + debugPrint "got patternlength: '$pat_name' (len=$pat_length)" + if {![dict exists $length($id) $pat_name] || [dict get $length($id) $pat_name] != $pat_length || $showpattern($id)} { + dict set length($id) $pat_name $pat_length + for {set i 0} {$i < $pat_length} {incr i} { + sendGui [concat $id EDIT getrow $pat_name $i] + } + } + } + row { + set pat_name [lindex $args 1] + if {$quirks_fix_int_floats} { + set row_num [expr {int([lindex $args 2])}] + } else { + set row_num [lindex $args 2] + } + set row [lrange $args 3 end] + debugPrint "got row: '$pat_name' ($row_num) {$row}" + setCellValueUI $id $pat_name $row_num -1 [expr {1+$row_num}] + for {set i 0} {$i < [llength $row]} {incr i} { + setCellValueUI $id $pat_name $row_num $i [lindex $row $i] + } + if {$row_num + 1 == [dict get $length($id) $pat_name]} { + if {$showpattern($id)} { + set showpattern($id) 0 + displayPattern_async $id $pat_name + } + } + } + cell { + set pat_name [lindex $args 1] + if {$quirks_fix_int_floats} { + set row_num [expr {int([lindex $args 2])}] + set col_num [expr {int([lindex $args 3])}] + } else { + set row_num [lindex $args 2] + set col_num [lindex $args 3] + } + set cell [lindex $args 4] + debugPrint "got cell: '$pat_name' ($row_num,$col_num) {$cell}" + debugPrint "dataVar = [getDataVar $id $pat_name]" + setCellValueUI $id $pat_name $row_num $col_num $cell + } + } + } +} diff --git a/composer/makefile b/composer/makefile deleted file mode 100644 index 9db256c..0000000 --- a/composer/makefile +++ /dev/null @@ -1,34 +0,0 @@ -DEBUG?=0 - -all: pd_linux - -.SUFFIXES: .pd_linux - -pd_linux: composer.pd_linux - -LINUXCFLAGS = -DPD -DUNIX -DPIC -fPIC \ - -funroll-loops -fomit-frame-pointer \ - -Wall -W -Wno-shadow -Wstrict-prototypes \ - -Wno-unused -Wno-parentheses -Wno-switch -LINUXINCLUDE = -I/usr/src/pd/0.41.4/src -I/usr/include -LINUXLDFLAGS = -export_dynamic -shared - -ifeq ($(DEBUG),1) - LINUXCFLAGS += -O0 -g -ggdb -DDEBUG - STRIP=test -f -else - LINUXCFLAGS += -O2 - STRIP=strip --strip-unneeded -endif - -composer.pd_linux: track.c pattern.c \ - track_proxy.c \ - composer.c common.h arraylist.h - $(CC) $(LINUXCFLAGS) $(LINUXINCLUDE) -o composer.o -c composer.c - $(LD) $(LINUXLDFLAGS) -o composer.pd_linux composer.o -lc -lm - $(STRIP) composer.pd_linux - -clean: - rm -f *.o *.pd_linux - - diff --git a/composer/pattern.c b/composer/pattern.c deleted file mode 100644 index 6772b6b..0000000 --- a/composer/pattern.c +++ /dev/null @@ -1,165 +0,0 @@ -/* ------------------------------------------------------------------------ */ -/* Copyright (c) 2009 Federico Ferri. */ -/* For information on usage and redistribution, and for a DISCLAIMER OF ALL */ -/* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ -/* */ -/* composer: a music composition framework for pure-data */ -/* */ -/* This program 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. */ -/* */ -/* See file LICENSE for further informations on licensing terms. */ -/* */ -/* This program 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 this program; if not, write to the Free Software Foundation, */ -/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* ------------------------------------------------------------------------ */ - -#include "common.h" - -static t_pattern* pattern_new(t_track* track, t_symbol* name, t_int rows) { - ArrayListGetByName(track->x_patterns, name, t_pattern*, obj); - debugprint("pattern_new - object lookup %s => " PTR, name->s_name, obj); - if(obj) return obj; - - t_pattern* x = (t_pattern*)getbytes(sizeof(t_pattern)); - x->x_name = name; - x->x_track = track; - ArrayListInit(x->x_rows, t_atom*, rows); - - int i; - for(i = 0; i < rows; i++) { - //debugprint("x->x_rows[%d] = " PTR, i, x->x_rows[i]); - pattern_new_empty_row(x); - //debugprint("x->x_rows[%d] <- " PTR, i, x->x_rows[i]); - } - - debugprint("created new pattern " PTR " with %d rows (x_rows = " PTR ")", x, x->x_rows_count, x->x_rows); - - // add pattern to track's pattern list - ArrayListAdd(x->x_track->x_patterns, t_pattern*, x); - return x; -} - -static t_pattern* pattern_clone(t_pattern* src, t_symbol* newname) { - t_pattern* x = (t_pattern*)getbytes(sizeof(t_pattern)); - x->x_name = newname; - x->x_track = src->x_track; - ArrayListInit(x->x_rows, t_atom*, src->x_rows_count); - - int i; - for(i = 0; i < src->x_rows_count; i++) { - ArrayListAdd(x->x_rows, t_atom*, pattern_clone_row(x, src->x_rows[i])); - } - - ArrayListAdd(x->x_track->x_patterns, t_pattern*, x); - return x; -} - -static void pattern_free(t_pattern* x) { - // free rows memory - ArrayListFree(x->x_rows, t_atom*); - // remove pattern from track's pattern list - ArrayListRemove(x->x_track->x_patterns, x); -} - -static void pattern_rename(t_pattern* x, t_symbol* newname) { - x->x_name = newname; -} - -static void pattern_resize(t_pattern *x, t_int newsize) { - debugprint("pattern_resize(" PTR ", %d)", x, newsize); - debugprint("initial size: %d", x->x_rows_count); - while(x->x_rows_count < newsize) - pattern_new_empty_row(x); - while(x->x_rows_count > newsize) - ArrayListRemoveByIndex(x->x_rows, x->x_rows_count - 1); - debugprint("final size: %d", x->x_rows_count); -} - -/* WARNING: do not call this for track with more than 1 pattern! - * Works only for the mastertrack (song_proxy) - */ -static void pattern_resize_cols(t_pattern* x, t_int newcols) { - int i,j; - for(j = 0; j < x->x_rows_count; j++) { - if(&x->x_rows[j]) - x->x_rows[j] = (t_atom*)resizebytes(x->x_rows[j], x->x_track->x_ncolumns, newcols); - else - x->x_rows[j] = (t_atom*)getbytes(sizeof(t_atom) * newcols); - } - if(newcols > x->x_track->x_ncolumns) { - for(j = 0; j < x->x_rows_count; j++) { - for(i = x->x_track->x_ncolumns; i < newcols; i++) - pattern_init_cell(&x->x_rows[j][i]); - } - } - x->x_track->x_ncolumns = newcols; -} - -static void pattern_init_cell(t_atom* a) { - if(a) SETSYMBOL(a, gensym("empty")); -} - -static void pattern_new_empty_row(t_pattern* x) { - t_atom* rowdata = (t_atom*)getbytes(sizeof(t_atom) * x->x_track->x_ncolumns); - int j; - for(j = 0; j < x->x_track->x_ncolumns; j++) - pattern_init_cell(&rowdata[j]); - ArrayListAdd(x->x_rows, t_atom*, rowdata); -} - -static t_atom* pattern_getrow(t_pattern* x, t_int row) { - debugprint("pattern_getrow(" PTR ", %d)", x, row); - row = WRAP(row, x->x_rows_count); - t_atom* rowdata = x->x_rows[row]; - return rowdata; -} - -static t_atom* pattern_clone_row(t_pattern* x, t_atom* rowdata) { - debugprint("pattern_clone_row(" PTR ", " PTR ")", x, rowdata); - t_atom* clone = (t_atom*)copybytes(rowdata, sizeof(t_atom) * x->x_track->x_ncolumns); - return clone; -} - -static t_atom* pattern_getcell(t_pattern* x, t_int row, t_int col) { - row = WRAP(row, x->x_rows_count); - col = WRAP(col, x->x_track->x_ncolumns); - return &(x->x_rows[row][col]); -} - -static void pattern_setrow(t_pattern* x, t_int row, t_atom* rowdata) { - debugprint("pattern_setrow(" PTR ", %d, " PTR ")", x, row, rowdata); - row = WRAP(row, x->x_rows_count); - //debugprint("x->x_rows[%d] = " PTR, row, x->x_rows[row]); - t_atom *myrowdata = x->x_rows[row]; - memcpy(myrowdata, rowdata, sizeof(t_atom) * x->x_track->x_ncolumns); - //debugprint("x->x_rows[%d] <- " PTR, row, x->x_rows[row]); -} - -static void pattern_setcell(t_pattern* x, t_int row, t_int col, t_atom* a) { - row = WRAP(row, x->x_rows_count); - col = WRAP(col, x->x_track->x_ncolumns); - //debugprint("about to write an atom (size=%d) at address " PTR, sizeof(t_atom), &(x->x_rows[row][col])); - memcpy(&(x->x_rows[row][col]), a, sizeof(t_atom)); -} - -static t_pattern* pattern_get(t_symbol* song_name, t_symbol* track_name, t_symbol* pattern_name) { - t_track* track = track_get(song_name, track_name); - if(!track || !track->x_patterns) return (t_pattern*) 0L; - ArrayListGetByName(track->x_patterns, pattern_name, t_pattern*, result); - return result; -} - -static int pattern_exists(t_symbol* song_name, t_symbol* track_name, t_symbol* pattern_name) { - return pattern_get(song_name, track_name, pattern_name) != 0L; -} diff --git a/composer/song.c b/composer/song.c deleted file mode 100644 index 6129181..0000000 --- a/composer/song.c +++ /dev/null @@ -1,104 +0,0 @@ -/* ------------------------------------------------------------------------ */ -/* Copyright (c) 2009 Federico Ferri. */ -/* For information on usage and redistribution, and for a DISCLAIMER OF ALL */ -/* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ -/* */ -/* composer: a music composition framework for pure-data */ -/* */ -/* This program 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. */ -/* */ -/* See file LICENSE for further informations on licensing terms. */ -/* */ -/* This program 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 this program; if not, write to the Free Software Foundation, */ -/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* ------------------------------------------------------------------------ */ - -#include "common.h" - -static t_song* song_new(t_symbol* song_name) { - ArrayListGetByName(songs, song_name, t_song*, obj); - debugprint("song_new - object lookup %s => " PTR, song_name->s_name, obj); - if(obj) return obj; - - t_song* x = (t_song*)getbytes(sizeof(t_song)); - x->x_name = song_name; - ArrayListInit(x->x_tracks, struct _track*, 16); - // mastertrack is named like the song - x->x_mastertrack = mastertrack_new(x, x->x_name, 0); - - debugprint("created a song object (" PTR "), " - "creation args: %s", - x, x->x_name->s_name); - - ArrayListAdd(songs, t_song*, x); - debugprint("registered song object to global song collection"); - return x; -} - -static void song_mastertrack_fix_cols(t_song* x) { - debugprint("song_mastertrack_fix_cols(" PTR "), new track count: %d", x, x->x_tracks_count); - debugprint("song='%s' mastertrack=" PTR, x->x_name->s_name, x->x_mastertrack); - debugprint("we have %d patterns, sir", x->x_mastertrack->x_patterns_count); - if(x->x_mastertrack->x_patterns_count < x->x_mastertrack->x_ncolumns) { - debugprint("song_mastertrack_fix_cols: still loading (apparently?), skipping."); - return; - } - song_internal_resize_cols(x, x->x_tracks_count); -} - -static void song_free(t_song* x) { - // free tracks memory - ArrayListFree(x->x_tracks, t_track*); - // remove song from global song collection - ArrayListRemove(songs, x); -} - -static void song_internal_resize_cols(t_song* x, t_int sz) { - int j; - for(j = 0; j < x->x_mastertrack->x_patterns_count; j++) { - if(j > 0) post("WARNING: mastertrack with more than one pattern!"); - pattern_resize_cols(x->x_mastertrack->x_patterns[j], sz); - } -} - -static t_song* song_get(t_symbol* song_name) { - ArrayListGetByName(songs, song_name, t_song*, result); - return result; -} - -static int song_exists(t_symbol* song_name) { - return song_get(song_name) != 0L; -} - -static void song_loaddata(t_song* x, int argc, t_atom* argv) { - if(argc < 2) { - error("song_loaddata: format error 1"); - return; - } - if(argv[0].a_type != A_SYMBOL || argv[1].a_type != A_FLOAT) { - error("song_loaddata: format error 2"); - } - t_symbol* name = argv[0].a_w.w_symbol; - t_int ntracks = (t_int)argv[1].a_w.w_float; - debugprint("song_loaddata: song='%s', tracks=%d", name->s_name, ntracks); - song_internal_resize_cols(x, ntracks); -} - -static void song_binbuf_save(t_song* t, t_symbol* selector, t_binbuf* b) { - // data format: - // SELECTOR DATA - - binbuf_addv(b, "sssi", selector, gensym("SONGINFO"), t->x_name, t->x_tracks_count); - binbuf_addv(b, ";"); -} diff --git a/composer/song_proxy.c b/composer/song_proxy.c deleted file mode 100644 index 00b1440..0000000 --- a/composer/song_proxy.c +++ /dev/null @@ -1,402 +0,0 @@ -/* ------------------------------------------------------------------------ */ -/* Copyright (c) 2009 Federico Ferri. */ -/* For information on usage and redistribution, and for a DISCLAIMER OF ALL */ -/* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ -/* */ -/* composer: a music composition framework for pure-data */ -/* */ -/* This program 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. */ -/* */ -/* See file LICENSE for further informations on licensing terms. */ -/* */ -/* This program 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 this program; if not, write to the Free Software Foundation, */ -/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* ------------------------------------------------------------------------ */ - -#include "common.h" - -t_class* song_proxy_class; - -static t_atom response_pattern_length[2]; -static t_atom response_cell[4]; -static t_atom* response_row; // TODO: memory leaks check -static size_t response_row_sz; - -void song_proxy_setup(void) { - debugprint("registering 'song' class..."); - song_proxy_class = class_new( - gensym("song"), - (t_newmethod)song_proxy_new, - (t_method)song_proxy_free, - sizeof(t_song_proxy), - CLASS_DEFAULT, //0, - A_SYMBOL, - 0 - ); - class_addfloat(song_proxy_class, song_proxy_float); - class_addanything(song_proxy_class, song_proxy_anything); - class_addmethod(song_proxy_class, (t_method)song_proxy_properties, \ - gensym("editor-open"), 0); - class_addmethod(song_proxy_class, (t_method)song_proxy_properties_close, \ - gensym("editor-close"), 0); - class_addmethod(song_proxy_class, (t_method)song_proxy_setrow, \ - gensym("setrow"), A_GIMME, 0); - class_addmethod(song_proxy_class, (t_method)song_proxy_getrow_o, \ - gensym("getrow"), A_SYMBOL, A_FLOAT, 0); - class_addmethod(song_proxy_class, (t_method)song_proxy_setcell, \ - gensym("setcell"), A_GIMME, 0); - class_addmethod(song_proxy_class, (t_method)song_proxy_getcell_o, \ - gensym("getcell"), A_SYMBOL, A_FLOAT, A_FLOAT, 0); - class_addmethod(song_proxy_class, (t_method)song_proxy_resizepattern, \ - gensym("resizepattern"), A_SYMBOL, A_FLOAT, 0); -#if PD_MINOR_VERSION >= 37 - class_setpropertiesfn(song_proxy_class, song_proxy_properties); - class_setsavefn(song_proxy_class, song_proxy_save); -#endif - class_sethelpsymbol(song_proxy_class, gensym("song.pd")); -} - -static t_song_proxy* song_proxy_new(t_symbol* song_name) { - t_song_proxy *x = (t_song_proxy*)pd_new(song_proxy_class); - x->outlet = outlet_new(&x->x_obj, &s_list); - x->x_song = song_new(song_name); - x->b_editor_open = 0; - char rcv_buf[80]; - sprintf(rcv_buf, "song_proxy-%s", x->x_song->x_name->s_name); - x->rcv = gensym(rcv_buf); - pd_bind(&x->x_obj.ob_pd, x->rcv); - - debugprint("created an instance of t_song_proxy: " PTR, x); - - song_proxy_properties_close((t_gobj*) x, NULL); - - pd_bind(&x->x_obj.ob_pd, gensym(SONG_SELECTOR)); - pd_bind(&x->x_obj.ob_pd, gensym(TRACK_SELECTOR)); - - debugprint("pd::composer::init %s %s %s %d %s %d\n", x->rcv->s_name, x->x_song->x_name->s_name, x->x_song->x_mastertrack->x_name->s_name, x->x_song->x_mastertrack->x_ncolumns, "Arrangement", DEBUG_BOOL); - sys_vgui("pd::composer::init %s %s %s %d %s %d\n", x->rcv->s_name, x->x_song->x_name->s_name, x->x_song->x_mastertrack->x_name->s_name, x->x_song->x_mastertrack->x_ncolumns, "Arrangement", DEBUG_BOOL); - - return x; -} - -static void song_proxy_free(t_song_proxy* x) { - song_proxy_properties_close((t_gobj*) x, NULL); - - pd_unbind(&x->x_obj.ob_pd, gensym(SONG_SELECTOR)); - pd_unbind(&x->x_obj.ob_pd, gensym(TRACK_SELECTOR)); - - /* LATER find a way to get SONG_SELECTOR unbound earlier (at end of load?) */ - /* Was this code needed? for what? - t_pd* x2; - while (x2 = pd_findbyclass(gensym(SONG_SELECTOR), song_proxy_class)) - pd_unbind(x2, gensym(SONG_SELECTOR));*/ - - pd_unbind(&x->x_obj.ob_pd, x->rcv); -} - -static t_atom* song_proxy_get_pattern_names(t_song_proxy* x) { - if(response_row) { - freebytes(response_row, response_row_sz * sizeof(t_atom)); - response_row = NULL; - response_row_sz = 0; - } - response_row_sz = track_get_pattern_count(x->x_song->x_mastertrack); - response_row = (t_atom*)getbytes(sizeof(t_atom) * response_row_sz); - track_get_pattern_names(x->x_song->x_mastertrack, response_row); - return response_row; -} - -static void song_proxy_float(t_song_proxy* x, t_floatarg f) { -} - -static void song_proxy_properties(t_gobj* z, t_glist* owner) { - t_song_proxy* x = (t_song_proxy*)z; - sys_vgui("pd::composer::openWindow %s\n", x->rcv->s_name); - x->b_editor_open = 1; -} - -static void song_proxy_properties_close(t_gobj* z, t_glist* owner) { - t_song_proxy* x = (t_song_proxy*)z; - debugprint("song_proxy_properties_close(" PTR ", " PTR ") [editor is %s]", z, owner, x->b_editor_open ? "open" : "closed"); - if(x->b_editor_open) { - debugprint("closing..."); - sys_vgui("pd::composer::closeWindow %s\n", x->rcv->s_name); - x->b_editor_open = 0; - } -} - -static void song_proxy_save(t_gobj* z, t_binbuf* b) { - t_song_proxy* x = (t_song_proxy*)z; - t_song* s = x->x_song; - t_track* t = s->x_mastertrack; - - binbuf_addv(b, "ssiiss;", gensym("#X"), gensym("obj"), - (t_int)x->x_obj.te_xpix, (t_int)x->x_obj.te_ypix, - gensym("song"), s->x_name); - - song_binbuf_save(s, gensym(SONG_SELECTOR), b); - - track_binbuf_save(t, gensym(TRACK_SELECTOR), b); -} - -static t_atom* song_proxy_gettracks(t_song_proxy* x) { - if(response_row) { - freebytes(response_row, response_row_sz * sizeof(t_atom)); - response_row = NULL; - response_row_sz = 0; - } - response_row_sz = x->x_song->x_tracks_count; - response_row = (t_atom*)getbytes(response_row_sz * sizeof(t_atom)); - int i; - for(i = 0; i < x->x_song->x_tracks_count; i++) { - SETSYMBOL(&response_row[i], x->x_song->x_tracks[i]->x_name); - } - return &response_row[0]; -} - -static void song_proxy_gettracks_o(t_song_proxy* x) { - t_atom* rsp = song_proxy_gettracks(x); - if(rsp) - outlet_list(x->outlet, &s_list, response_row_sz, rsp); -} - -static t_int song_proxy_gettracks_count(t_song_proxy* x) { - return x->x_song->x_tracks_count; -} - -static void song_proxy_gettracks_count_o(t_song_proxy* x) { - outlet_float(x->outlet, (t_float)song_proxy_gettracks_count(x)); -} - -static void song_proxy_anything(t_song_proxy* x, t_symbol* s, int argc, t_atom* argv) { - debugprint("song_proxy_anything(" PTR ", %s, %d, " PTR ")", x, s->s_name, argc, argv); - - if(s == gensym("DATA")) { - song_proxy_loaddata(x, s, argc, argv); - return; - } else if(s == gensym("EDIT")) { - song_proxy_editcmd(x, s, argc, argv); - return; - } else if(s == gensym("SONGINFO")) { - song_proxy_loadsonginfo(x, s, argc, argv); - return; - } else { - error("unrecognized command for anything method: %s ", s->s_name); - return; - } -} - -static void song_proxy_loadsonginfo(t_song_proxy* x, t_symbol* s, int argc, t_atom* argv) { - song_loaddata(x->x_song, argc, argv); -} - -static void song_proxy_loaddata(t_song_proxy* x, t_symbol* s, int argc, t_atom* argv) { - track_loaddata(x->x_song->x_mastertrack, argc, argv); -} - -static t_atom* song_proxy_getpatternlength(t_song_proxy* x, t_symbol* pat_name) { - ArrayListGetByName(x->x_song->x_mastertrack->x_patterns, pat_name, t_pattern*, pat); - if(!pat) { - error("song: getpatternlength: no such pattern: '%s'", pat_name->s_name); - return NULL; - } - SETSYMBOL(&response_pattern_length[0], pat->x_name); - SETFLOAT(&response_pattern_length[1], pat->x_rows_count); - return &response_pattern_length[0]; -} - -static void song_proxy_editcmd(t_song_proxy* x, t_symbol* s_, int argc, t_atom* argv_) { - if(argc < 1 || argv_[0].a_type != A_SYMBOL) { - error("track: editcmd: missing method selector"); - return; - } - /*if(argc < 2) { - error("track: editcmd: missing data after selector"); - return; - }*/ - - // route -> selector - t_symbol* s = argv_[0].a_w.w_symbol; - t_atom* argv = &argv_[1]; - argc--; - - t_symbol *s1 = (argc >= 1 && argv[0].a_type == A_SYMBOL) ? argv[0].a_w.w_symbol : NULL; - t_symbol *s2 = (argc >= 2 && argv[1].a_type == A_SYMBOL) ? argv[1].a_w.w_symbol : NULL; - t_float f2 = (argc >= 2 && argv[1].a_type == A_FLOAT) ? argv[1].a_w.w_float : 0; - t_float f3 = (argc >= 3 && argv[2].a_type == A_FLOAT) ? argv[2].a_w.w_float : 0; - - t_pattern* p = NULL; - int i,j; - - if(s == gensym("editor-open")) { - song_proxy_properties((t_gobj*) x, NULL); - } else if(s == gensym("editor-close")) { - song_proxy_properties_close((t_gobj*) x, NULL); - } else if(s == gensym("getpatterns")) { - t_atom* rsp = song_proxy_get_pattern_names(x); - song_proxy_sendgui(x, gensym("patterns"), response_row_sz, rsp); - } else if(s == gensym("gettracks")) { - t_atom* rsp = song_proxy_gettracks(x); - song_proxy_sendgui(x, gensym("tracks"), response_row_sz, rsp); - } else if(s == gensym("gettrackscount")) { - t_atom a; - SETFLOAT(&a, (t_float)song_proxy_gettracks_count(x)); - song_proxy_sendgui(x, gensym("trackscount"), 1, &a); - } else if(s == gensym("getpatternlength")) { - song_proxy_sendgui(x, gensym("patternlength"), 2, song_proxy_getpatternlength(x, s1)); - } else if(s == gensym("getrow")) { - song_proxy_sendgui(x, gensym("row"), 2 + x->x_song->x_mastertrack->x_ncolumns, song_proxy_getrow_with_header(x, s1, f2)); - } else if(s == gensym("setrow")) { - song_proxy_setrow(x, s, argc, argv); - } else if(s == gensym("getcell")) { - song_proxy_sendgui(x, gensym("cell"), 4, song_proxy_getcell_with_header(x, s1, f2, f3)); - } else if(s == gensym("setcell")) { - song_proxy_setcell(x, s, argc, argv); - } else if(s == gensym("resizepattern")) { - p = song_proxy_resizepattern(x, s1, f2); - if(p) { - song_proxy_sendgui(x, gensym("patternlength"), 2, song_proxy_getpatternlength(x, p->x_name)); - } - } else { - error("track: editcmd: unknown command: %s", s->s_name); - } -} - -static void song_proxy_sendgui(t_song_proxy* x, t_symbol* s, int argc, t_atom* argv) { - static const unsigned int bufsz = 8*MAXPDSTRING; - char buf[bufsz]; - list_snconvf(buf, bufsz, s, argc, argv); - debugprint("pd::composer::dispatch %s %s", x->rcv->s_name, buf); - sys_vgui("pd::composer::dispatch %s %s\n", x->rcv->s_name, buf); -} - -static void song_proxy_setrow(t_song_proxy* x, t_symbol* sel, int argc, t_atom* argv) { - if(argc < 2 || argv[0].a_type != A_SYMBOL || argv[1].a_type != A_FLOAT) { - error("song: setrow: usage: setrow ..."); - return; - } - if((argc - 2) != x->x_song->x_mastertrack->x_ncolumns) { - post("argc=%d, ncolumns=%d", argc, x->x_song->x_mastertrack->x_ncolumns); - error("track: setrow: input error: must provide exactly %d elements for the row", x->x_song->x_mastertrack->x_ncolumns); - return; - } - t_symbol* pat_name = argv[0].a_w.w_symbol; - t_int rownum = (t_int)argv[1].a_w.w_float; - ArrayListGetByName(x->x_song->x_mastertrack->x_patterns, pat_name, t_pattern*, pat); - if(!pat) { - error("track: setrow: no such pattern: '%s'", pat_name->s_name); - return; - } - pattern_setrow(pat, rownum, &argv[2]); -} - -static t_atom* song_proxy_getrow(t_song_proxy* x, t_symbol* pat_name, t_floatarg rownum) { - ArrayListGetByName(x->x_song->x_mastertrack->x_patterns, pat_name, t_pattern*, pat); - if(!pat) { - error("song: getrow: no such pattern: '%s'", pat_name->s_name); - return NULL; - } - t_atom* row = pattern_getrow(pat, (t_int)rownum); - debugprint("song_proxy_getrow returning " PTR, row); - return row; -} - -static t_atom* song_proxy_getrow_with_header(t_song_proxy* x, t_symbol* pat_name, t_floatarg rownum) { - if(response_row) { - freebytes(response_row, response_row_sz * sizeof(t_atom)); - response_row = NULL; - response_row_sz = 0; - } - - t_atom* row = song_proxy_getrow(x, pat_name, rownum); - if(!row) { - error("song: getrow: no such pattern: '%s'", pat_name->s_name); - return NULL; - } - fprintf(stderr, "GOT A ROW " PTR ", 2 + %d (=? %d) columns, last a_type = %d\n", (long unsigned int)row, (int)x->x_song->x_mastertrack->x_ncolumns, (int)x->x_song->x_tracks_count, 0); - response_row_sz = x->x_song->x_mastertrack->x_ncolumns + 2; - t_atom* response_row = (t_atom*)getbytes(response_row_sz * sizeof(t_atom)); - SETSYMBOL(&response_row[0], pat_name); - SETFLOAT(&response_row[1], rownum); - memcpy(&response_row[2], row, sizeof(t_atom) * x->x_song->x_mastertrack->x_ncolumns); - if(response_row[2].a_type == A_SYMBOL) - fprintf(stderr, "VALUE[2] = %s\n", response_row[2].a_w.w_symbol->s_name); - else if(response_row[2].a_type == A_FLOAT) - fprintf(stderr, "VALUE[2] = %f\n", response_row[2].a_w.w_float); - else - fprintf(stderr, "VALUE[2] = ? (type = %d)\n", response_row[2].a_type); - - return &response_row[0]; -} - -static void song_proxy_getrow_o(t_song_proxy* x, t_symbol* pat_name, t_floatarg rownum) { - t_atom* row = song_proxy_getrow(x, pat_name, rownum); - if(row) - outlet_list(x->outlet, &s_list, x->x_song->x_mastertrack->x_ncolumns, row); -} - -static void song_proxy_setcell(t_song_proxy* x, t_symbol* sel, int argc, t_atom* argv) { - debugprint("song_proxy_setcell, s=%s", sel->s_name); - if(argc < 4 || argv[0].a_type != A_SYMBOL || argv[1].a_type != A_FLOAT || argv[2].a_type != A_FLOAT) { - error("song: setcell: usage: setcell "); - return; - } - t_symbol* pat_name = argv[0].a_w.w_symbol; - t_int rownum = (t_int)argv[1].a_w.w_float; - t_int colnum = (t_int)argv[2].a_w.w_float; - ArrayListGetByName(x->x_song->x_mastertrack->x_patterns, pat_name, t_pattern*, pat); - if(!pat) { - error("song: setcell: no such pattern: '%s'", pat_name->s_name); - return; - } - pattern_setcell(pat, (t_int)rownum, (t_int)colnum, &argv[3]); -} - -static t_atom* song_proxy_getcell(t_song_proxy* x, t_symbol* pat_name, t_floatarg rownum, t_floatarg colnum) { - ArrayListGetByName(x->x_song->x_mastertrack->x_patterns, pat_name, t_pattern*, pat); - if(!pat) { - error("song: getcell: no such pattern: '%s'", pat_name->s_name); - return NULL; - } - return pattern_getcell(pat, (t_int)rownum, (t_int)colnum); -} - -static t_atom* song_proxy_getcell_with_header(t_song_proxy* x, t_symbol* pat_name, t_floatarg rownum, t_floatarg colnum) { - t_atom* cell = song_proxy_getcell(x, pat_name, rownum, colnum); - if(!cell) { - error("song: getcell: no such pattern: '%s'", pat_name->s_name); - return NULL; - } - SETSYMBOL(&response_cell[0], pat_name); - SETFLOAT(&response_cell[1], rownum); - SETFLOAT(&response_cell[2], colnum); - memcpy(&response_cell[3], cell, sizeof(t_atom)); - return &response_cell[0]; -} - -static void song_proxy_getcell_o(t_song_proxy* x, t_symbol* pat_name, t_floatarg rownum, t_floatarg colnum) { - t_atom* cell = song_proxy_getcell(x, pat_name, rownum, colnum); - if(cell) - outlet_list(x->outlet, &s_list, 1, cell); -} - -static t_pattern* song_proxy_resizepattern(t_song_proxy* x, t_symbol* name, t_floatarg rows) { - ArrayListGetByName(x->x_song->x_mastertrack->x_patterns, name, t_pattern*, pat); - if(!pat) { - error("song: resizepattern: no such pattern: '%s'", name->s_name); - return NULL; - } - pattern_resize(pat, (t_int)rows); - return pat; -} diff --git a/composer/track.c b/composer/track.c deleted file mode 100644 index 477fdfd..0000000 --- a/composer/track.c +++ /dev/null @@ -1,204 +0,0 @@ -/* ------------------------------------------------------------------------ */ -/* Copyright (c) 2009 Federico Ferri. */ -/* For information on usage and redistribution, and for a DISCLAIMER OF ALL */ -/* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ -/* */ -/* composer: a music composition framework for pure-data */ -/* */ -/* This program 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. */ -/* */ -/* See file LICENSE for further informations on licensing terms. */ -/* */ -/* This program 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 this program; if not, write to the Free Software Foundation, */ -/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* ------------------------------------------------------------------------ */ - -#include "common.h" - -static t_track* track_new(t_symbol* song_name, t_symbol* track_name, t_int columns) { - debugprint("track_new(%s, %s, %d)", song_name->s_name, track_name->s_name, columns); - t_song* song = song_new(song_name); - t_track* t = song_create_track(song, track_name, columns); - - // add track to song's track list - ArrayListAdd(song->x_tracks, t_track*, t); - song_mastertrack_fix_cols(song); - - return t; -} - -static t_track* mastertrack_new(t_song* song, t_symbol* track_name, t_int columns) { - debugprint("mastertrack_new(%s, %s, %d)", song->x_name->s_name, track_name->s_name, columns); - t_track* t = song_create_track(song, track_name, columns); - debugprint("mastertrack_new add pattern"); - ArrayListAdd(t->x_patterns, t_pattern*, pattern_new(t, gensym("Arrangement"), 16)); - return t; -} - -// both a song method and the track constructor: -static t_track* song_create_track(t_song* song, t_symbol* track_name, t_int columns) { - ArrayListGetByName(song->x_tracks, track_name, t_track*, obj); - debugprint("song_create_track - object lookup %s, %s, %d => " PTR, - song->x_name->s_name, track_name->s_name, columns, obj); - if(obj) return obj; - - t_track* x = (t_track*)getbytes(sizeof(t_track)); - x->x_name = track_name; - x->x_song = song; - x->x_ncolumns = columns; - ArrayListInit(x->x_patterns, struct _pattern*, 4); - x->x_currentpat = 0; - - debugprint("created a track object (" PTR "), " - "creation args: %s, %s, %d", - x, x->x_song->x_name->s_name, x->x_name->s_name, x->x_ncolumns); - - debugprint("song_create_track returns " PTR, x); - return x; -} - -static void track_free(t_track* x) { - // free patterns memory - ArrayListFree(x->x_patterns, t_pattern*); - // remove track from song's track list - ArrayListRemove(x->x_song->x_tracks, x); -} - -static t_int track_get_pattern_count(t_track* x) { - return x->x_patterns_count; -} - -static void track_get_pattern_names(t_track* x, t_atom* /* OUT */ out) { - int i; - for(i = 0; i < x->x_patterns_count; i++) { - SETSYMBOL(&out[i], x->x_patterns[i]->x_name); - } -} - -static t_track* track_get(t_symbol* song_name, t_symbol* track_name) { - t_song* song = song_get(song_name); - if(!song || !song->x_tracks) return (t_track*) 0L; - ArrayListGetByName(song->x_tracks, track_name, t_track*, result); - return result; -} - -static int track_exists(t_symbol* song_name, t_symbol* track_name) { - return track_get(song_name, track_name) != 0L; -} - -static void track_loaddata(t_track* x, int argc, t_atom* argv) { - debugprint("track_loaddata(" PTR ", %d, " PTR ")", x, argc, argv); - int i,base; - base = 0; - - if(argc < (base+2) || argv[base].a_type != A_SYMBOL || argv[base+1].a_type != A_SYMBOL) { - error("track: data format error 1"); - return; - } - t_symbol* song_name = argv[base+0].a_w.w_symbol; - t_symbol* track_name = argv[base+1].a_w.w_symbol; - base += 2; - - if(x->x_song->x_name != song_name) { - debugprint("WARNING: discarding data from another song: %s", song_name->s_name); - return; - } - - if(x->x_name != track_name) { - debugprint("WARNING: discarding data from another track: %s", track_name->s_name); - return; - } - - t_song* song = song_get(song_name); - if(!song) { - error("track: song '%s' does not exist", song_name->s_name); - return; - } - - debugprint("track_loaddata: song='%s', track='%s'", song_name->s_name, track_name->s_name); - - if(argc < (base+1) || argv[base].a_type != A_FLOAT) { - error("track: data format error 2"); - return; - } - t_int npatterns = (t_int)argv[base].a_w.w_float; - base += 1; - - debugprint("track_loaddata: %d patterns to read", npatterns); - - t_symbol* patname; - t_int patrows; - t_pattern* pat; - - debugprint("track_loaddata(" PTR ", %d, " PTR ")", x, argc, argv); - for(i = 0; i < npatterns; i++) { - debugprint("reading pattern %d...", i); - if(argc < (base + 2)) { - error("track: data format error 3 (i=%d)", i); - return; - } - if(argv[base+0].a_type != A_SYMBOL || argv[base+1].a_type != A_FLOAT) { - error("track: data format error 4 (i=%d)", i); - return; - } - patname = argv[base+0].a_w.w_symbol; - patrows = (t_int)argv[base+1].a_w.w_float; - debugprint("pattern %d: %s-%s-%s, length=%d, RxC=%d", i, - song_name->s_name, track_name->s_name, patname->s_name, - patrows, patrows * x->x_ncolumns); - base += 2; - if(argc >= (base + patrows * x->x_ncolumns) && patrows > 0) { - pat = pattern_new(x, patname, patrows); - debugprint("created new pattern " PTR " ('%s', %d rows) for track " PTR, pat, patname->s_name, patrows, x); - int j,h,k; - for(h = 0, j = base; j < (base + patrows * x->x_ncolumns); j += x->x_ncolumns, h++) { - debugprint(" working on row %d", h); - for(k = 0; k < x->x_ncolumns; k++) { - pattern_setcell(pat, h, k, &argv[j+k]); - } - } - base += patrows * x->x_ncolumns; - } else { - error("track: data format error 8 (i=%d)", i); - return; - } - } -} - -static void track_binbuf_save(t_track* t, t_symbol* selector, t_binbuf* b) { - // data format: - // SELECTOR DATA [ RxC_atoms]*n - - binbuf_addv(b, "ssssi", selector, gensym("DATA"), - t->x_song->x_name, t->x_name, t->x_patterns_count); - - int i,j,k; - for(i = 0; i < t->x_patterns_count; i++) { - t_pattern* pat = t->x_patterns[i]; - binbuf_addv(b, "si", pat->x_name, pat->x_rows_count); - for(j = 0; j < pat->x_rows_count; j++) { - for(k = 0; k < t->x_ncolumns; k++) { - switch(pat->x_rows[j][k].a_type) { - case A_FLOAT: binbuf_addv(b, "f", pat->x_rows[j][k].a_w.w_float); break; - case A_SYMBOL: binbuf_addv(b, "s", pat->x_rows[j][k].a_w.w_symbol); break; - case A_NULL: binbuf_addv(b, "s", gensym("empty")); break; - default: binbuf_addv(b, "s", gensym("unknown")); break; - } - } - //binbuf_add(b, t->x_ncolumns, &pat->x_rows[j]); - } - } - - binbuf_addv(b, ";"); -} diff --git a/composer/track_proxy.c b/composer/track_proxy.c deleted file mode 100644 index 509cccb..0000000 --- a/composer/track_proxy.c +++ /dev/null @@ -1,441 +0,0 @@ -/* ------------------------------------------------------------------------ */ -/* Copyright (c) 2009 Federico Ferri. */ -/* For information on usage and redistribution, and for a DISCLAIMER OF ALL */ -/* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ -/* */ -/* composer: a music composition framework for pure-data */ -/* */ -/* This program 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. */ -/* */ -/* See file LICENSE for further informations on licensing terms. */ -/* */ -/* This program 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 this program; if not, write to the Free Software Foundation, */ -/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* ------------------------------------------------------------------------ */ - -#include "common.h" - -t_class* track_proxy_class; - -static t_atom response_pattern_length[2]; -static t_atom response_cell[4]; -static t_atom* response_row; // TODO: memory leaks check -static size_t response_row_sz; - -void track_proxy_setup(void) { - debugprint("registering 'track' class..."); - ArrayListInit(songs, t_song*, 10); - track_proxy_class = class_new( - gensym("track"), - (t_newmethod)track_proxy_new, - (t_method)track_proxy_free, - sizeof(t_track_proxy), - CLASS_DEFAULT, //0, - A_SYMBOL, A_SYMBOL, A_FLOAT, - 0 - ); - class_addfloat(track_proxy_class, track_proxy_float); - class_addanything(track_proxy_class, track_proxy_anything); - class_addmethod(track_proxy_class, (t_method)track_proxy_properties, \ - gensym("editor-open"), 0); - class_addmethod(track_proxy_class, (t_method)track_proxy_properties_close, \ - gensym("editor-close"), 0); - class_addmethod(track_proxy_class, (t_method)track_proxy_reload, \ - gensym("reload"), 0); - class_addmethod(track_proxy_class, (t_method)track_proxy_setrow, \ - gensym("setrow"), A_GIMME, 0); - class_addmethod(track_proxy_class, (t_method)track_proxy_getrow_o, \ - gensym("getrow"), A_SYMBOL, A_FLOAT, 0); - class_addmethod(track_proxy_class, (t_method)track_proxy_setcell, \ - gensym("setcell"), A_GIMME, 0); - class_addmethod(track_proxy_class, (t_method)track_proxy_getcell_o, \ - gensym("getcell"), A_SYMBOL, A_FLOAT, A_FLOAT, 0); - class_addmethod(track_proxy_class, (t_method)track_proxy_addpattern, \ - gensym("addpattern"), A_SYMBOL, A_FLOAT, 0); - class_addmethod(track_proxy_class, (t_method)track_proxy_removepattern, \ - gensym("removepattern"), A_SYMBOL, 0); - class_addmethod(track_proxy_class, (t_method)track_proxy_resizepattern, \ - gensym("resizepattern"), A_SYMBOL, A_FLOAT, 0); - class_addmethod(track_proxy_class, (t_method)track_proxy_renamepattern, \ - gensym("renamepattern"), A_SYMBOL, A_SYMBOL, 0); - class_addmethod(track_proxy_class, (t_method)track_proxy_copypattern, \ - gensym("copypattern"), A_SYMBOL, A_SYMBOL, 0); -#if PD_MINOR_VERSION >= 37 - class_setpropertiesfn(track_proxy_class, track_proxy_properties); - class_setsavefn(track_proxy_class, track_proxy_save); -#endif - class_sethelpsymbol(track_proxy_class, gensym("track.pd")); -} - -static t_track_proxy* track_proxy_new(t_symbol* song_name, t_symbol* track_name, t_floatarg cols) { - t_track_proxy *x = (t_track_proxy*)pd_new(track_proxy_class); - x->outlet = outlet_new(&x->x_obj, &s_list); - x->x_track = track_new(song_name, track_name, (t_int)cols); - x->b_editor_open = 0; - char rcv_buf[80]; - sprintf(rcv_buf, "track_proxy-%s-%s", x->x_track->x_song->x_name->s_name, x->x_track->x_name->s_name); - x->rcv = gensym(rcv_buf); - pd_bind(&x->x_obj.ob_pd, x->rcv); - debugprint("created an instance of t_track_proxy " PTR ", to_track=" PTR ", n=%s", - x, x->x_track, x->x_track->x_name->s_name); - - track_proxy_properties_close((t_gobj*) x, NULL); - - pd_bind(&x->x_obj.ob_pd, gensym(TRACK_SELECTOR)); - - debugprint("pd::composer::init %s %s %s %d %s %d\n", x->rcv->s_name, x->x_track->x_song->x_name->s_name, x->x_track->x_name->s_name, x->x_track->x_ncolumns, "NULL", DEBUG_BOOL); - sys_vgui("pd::composer::init %s %s %s %d %s %d\n", x->rcv->s_name, x->x_track->x_song->x_name->s_name, x->x_track->x_name->s_name, x->x_track->x_ncolumns, "NULL", DEBUG_BOOL); - - return x; -} - -static void track_proxy_free(t_track_proxy* x) { - track_proxy_properties_close((t_gobj*) x, NULL); - - pd_unbind(&x->x_obj.ob_pd, gensym(TRACK_SELECTOR)); - /* LATER find a way to get TRACK_SELECTOR unbound earlier (at end of load?) */ - t_pd* x2; - while (x2 = pd_findbyclass(gensym(TRACK_SELECTOR), track_proxy_class)) - pd_unbind(x2, gensym(TRACK_SELECTOR)); - - pd_unbind(&x->x_obj.ob_pd, x->rcv); -} - -static t_atom* track_proxy_get_pattern_names(t_track_proxy* x) { - if(response_row) { - freebytes(response_row, response_row_sz * sizeof(t_atom)); - response_row = NULL; - response_row_sz = 0; - } - response_row_sz = track_get_pattern_count(x->x_track); - response_row = (t_atom*)getbytes(sizeof(t_atom) * response_row_sz); - track_get_pattern_names(x->x_track, response_row); - return response_row; -} - -static void track_proxy_reload(t_track_proxy* x) { - sys_vgui("source {window.tk}\n"); -} - -static void track_proxy_properties(t_gobj* z, t_glist* owner) { - t_track_proxy* x = (t_track_proxy*)z; - sys_vgui("pd::composer::openWindow %s\n", x->rcv->s_name); - x->b_editor_open = 1; -} - -static void track_proxy_properties_close(t_gobj* z, t_glist* owner) { - t_track_proxy* x = (t_track_proxy*)z; - debugprint("track_proxy_properties_close(" PTR ", " PTR ") [editor is %s]", z, owner, x->b_editor_open ? "open" : "closed"); - if(x->b_editor_open) { - debugprint("closing..."); - sys_vgui("pd::composer::closeWindow %s\n", x->rcv->s_name); - x->b_editor_open = 0; - } -} - -static void track_proxy_save(t_gobj* z, t_binbuf* b) { - t_track_proxy* x = (t_track_proxy*)z; - t_track* t = x->x_track; - - binbuf_addv(b, "ssiisssi;", gensym("#X"), gensym("obj"), - (t_int)x->x_obj.te_xpix, (t_int)x->x_obj.te_ypix, - gensym("track"), t->x_song->x_name, t->x_name, t->x_ncolumns); - - track_binbuf_save(t, gensym(TRACK_SELECTOR), b); -} - -static void track_proxy_sendrow(t_track_proxy* x, t_pattern* pat, t_int row) { - t_track* t = x->x_track; - if(row < 0) row = 0; - row = row % pat->x_rows_count; - outlet_list(x->outlet, &s_list, t->x_ncolumns, pat->x_rows[row]); -} - -static void track_proxy_anything(t_track_proxy* x, t_symbol* s, int argc, t_atom* argv) { - debugprint("track_proxy_anything(" PTR ", %s, %d, " PTR ")", x, s->s_name, argc, argv); - - if(s == gensym("DATA")) { - track_proxy_loaddata(x, s, argc, argv); - return; - } else if(s == gensym("EDIT")) { - track_proxy_editcmd(x, s, argc, argv); - return; - } else { - error("unrecognized command for anything method: %s ", s->s_name); - return; - } -} - -static void track_proxy_loaddata(t_track_proxy* x, t_symbol* s, int argc, t_atom* argv) { - track_loaddata(x->x_track, argc, argv); -} - -static t_atom* track_proxy_getpatternlength(t_track_proxy* x, t_symbol* pat_name) { - ArrayListGetByName(x->x_track->x_patterns, pat_name, t_pattern*, pat); - if(!pat) { - error("track: getpatternlength: no such pattern: '%s'", pat_name->s_name); - return NULL; - } - SETSYMBOL(&response_pattern_length[0], pat->x_name); - SETFLOAT(&response_pattern_length[1], pat->x_rows_count); - return &response_pattern_length[0]; -} - -static void track_proxy_editcmd(t_track_proxy* x, t_symbol* s_, int argc, t_atom* argv_) { - if(argc < 1 || argv_[0].a_type != A_SYMBOL) { - error("track: editcmd: missing method selector"); - return; - } - /*if(argc < 2) { - error("track: editcmd: missing data after selector"); - return; - }*/ - - // route -> selector - t_symbol* s = argv_[0].a_w.w_symbol; - t_atom* argv = &argv_[1]; - argc--; - - t_symbol *s1 = (argc >= 1 && argv[0].a_type == A_SYMBOL) ? argv[0].a_w.w_symbol : NULL; - t_symbol *s2 = (argc >= 2 && argv[1].a_type == A_SYMBOL) ? argv[1].a_w.w_symbol : NULL; - t_float f2 = (argc >= 2 && argv[1].a_type == A_FLOAT) ? argv[1].a_w.w_float : 0; - t_float f3 = (argc >= 3 && argv[2].a_type == A_FLOAT) ? argv[2].a_w.w_float : 0; - - t_pattern* p = NULL; - int i,j; - - if(s == gensym("editor-open")) { - track_proxy_properties((t_gobj*) x, NULL); - } else if(s == gensym("editor-close")) { - track_proxy_properties_close((t_gobj*) x, NULL); - } else if(s == gensym("getpatterns")) { - t_atom* rsp = track_proxy_get_pattern_names(x); - track_proxy_sendgui(x, gensym("patterns"), response_row_sz, rsp); - } else if(s == gensym("getpatternlength")) { - track_proxy_sendgui(x, gensym("patternlength"), 2, track_proxy_getpatternlength(x, s1)); - } else if(s == gensym("getrow")) { - t_atom* rsp = track_proxy_getrow_with_header(x, s1, f2); - track_proxy_sendgui(x, gensym("row"), response_row_sz, rsp); - } else if(s == gensym("setrow")) { - track_proxy_setrow(x, s, argc, argv); - } else if(s == gensym("getcell")) { - track_proxy_sendgui(x, gensym("cell"), 4, track_proxy_getcell_with_header(x, s1, f2, f3)); - } else if(s == gensym("setcell")) { - track_proxy_setcell(x, s, argc, argv); - } else if(s == gensym("addpattern")) { - p = track_proxy_addpattern(x, s1, f2); - if(p) { - t_atom* rsp = track_proxy_get_pattern_names(x); - track_proxy_sendgui(x, gensym("patterns"), response_row_sz, rsp); - } - } else if(s == gensym("removepattern")) { - j = track_proxy_removepattern(x, s1); - if(j) { - t_atom* rsp = track_proxy_get_pattern_names(x); - track_proxy_sendgui(x, gensym("patterns"), response_row_sz, rsp); - } - } else if(s == gensym("resizepattern")) { - p = track_proxy_resizepattern(x, s1, f2); - if(p) { - track_proxy_sendgui(x, gensym("patternlength"), 2, track_proxy_getpatternlength(x, p->x_name)); - } - } else if(s == gensym("renamepattern")) { - p = track_proxy_renamepattern(x, s1, s2); - if(p) { - t_atom* rsp = track_proxy_get_pattern_names(x); - track_proxy_sendgui(x, gensym("patterns"), response_row_sz, rsp); - } - } else if(s == gensym("copypattern")) { - p = track_proxy_copypattern(x, s1, s2); - if(p) { - t_atom* rsp = track_proxy_get_pattern_names(x); - track_proxy_sendgui(x, gensym("patterns"), response_row_sz, rsp); - } - } else if(s == gensym("gettracks")) { - // dummy STFU - } else { - error("track: editcmd: unknown command: %s", s->s_name); - } -} - -static void track_proxy_sendgui(t_track_proxy* x, t_symbol* s, int argc, t_atom* argv) { - static const unsigned int bufsz = 8*MAXPDSTRING; - char buf[bufsz]; - list_snconvf(buf, bufsz, s, argc, argv); - debugprint("pd::composer::dispatch %s %s", x->rcv->s_name, buf); - sys_vgui("pd::composer::dispatch %s %s\n", x->rcv->s_name, buf); -} - -static void track_proxy_float(t_track_proxy* x, t_floatarg f) { - t_track* t = x->x_track; - if(t->x_patterns_count < 1) return; - - t_int curpat_i = (t_int) t->x_currentpat; - - if(curpat_i < 0) curpat_i = 0; - curpat_i = curpat_i % t->x_patterns_count; - - t_pattern* curpat = t->x_patterns[curpat_i]; - track_proxy_sendrow(x, curpat, (t_int) f); -} - -static void track_proxy_setrow(t_track_proxy* x, t_symbol* sel, int argc, t_atom* argv) { - if(argc < 2 || argv[0].a_type != A_SYMBOL || argv[1].a_type != A_FLOAT) { - error("track: setrow: usage: setrow ..."); - return; - } - if((argc - 2) != x->x_track->x_ncolumns) { - post("argc=%d, ncolumns=%d", argc, x->x_track->x_ncolumns); - error("track: setrow: input error: must provide exactly %d elements for the row", x->x_track->x_ncolumns); - return; - } - t_symbol* pat_name = argv[0].a_w.w_symbol; - t_int rownum = (t_int)argv[1].a_w.w_float; - ArrayListGetByName(x->x_track->x_patterns, pat_name, t_pattern*, pat); - if(!pat) { - error("track: setrow: no such pattern: '%s'", pat_name->s_name); - return; - } - pattern_setrow(pat, rownum, &argv[2]); -} - -static t_atom* track_proxy_getrow(t_track_proxy* x, t_symbol* pat_name, t_floatarg rownum) { - ArrayListGetByName(x->x_track->x_patterns, pat_name, t_pattern*, pat); - if(!pat) { - error("track: getrow: no such pattern: '%s'", pat_name->s_name); - return NULL; - } - t_atom* row = pattern_getrow(pat, (t_int)rownum); - debugprint("track_proxy_getrow returning " PTR, row); - return row; -} - -static t_atom* track_proxy_getrow_with_header(t_track_proxy* x, t_symbol* pat_name, t_floatarg rownum) { - if(response_row) { - freebytes(response_row, response_row_sz * sizeof(t_atom)); - response_row = NULL; - response_row_sz = 0; - } - - t_atom* row = track_proxy_getrow(x, pat_name, rownum); - if(!row) { - error("track: getrow: no such pattern: '%s'", pat_name->s_name); - return NULL; - } - response_row_sz = x->x_track->x_ncolumns + 2; - t_atom* response_row = (t_atom*)getbytes(response_row_sz * sizeof(t_atom)); - SETSYMBOL(&response_row[0], pat_name); - SETFLOAT(&response_row[1], rownum); - memcpy(&response_row[2], row, sizeof(t_atom) * x->x_track->x_ncolumns); - return &response_row[0]; -} - -static void track_proxy_getrow_o(t_track_proxy* x, t_symbol* pat_name, t_floatarg rownum) { - t_atom* row = track_proxy_getrow(x, pat_name, rownum); - if(row) - outlet_list(x->outlet, &s_list, x->x_track->x_ncolumns, row); -} - -static void track_proxy_setcell(t_track_proxy* x, t_symbol* sel, int argc, t_atom* argv) { - debugprint("track_proxy_setcell, s=%s", sel->s_name); - if(argc < 4 || argv[0].a_type != A_SYMBOL || argv[1].a_type != A_FLOAT || argv[2].a_type != A_FLOAT) { - error("track: setcell: usage: setcell "); - return; - } - t_symbol* pat_name = argv[0].a_w.w_symbol; - t_int rownum = (t_int)argv[1].a_w.w_float; - t_int colnum = (t_int)argv[2].a_w.w_float; - ArrayListGetByName(x->x_track->x_patterns, pat_name, t_pattern*, pat); - if(!pat) { - error("track: setcell: no such pattern: '%s'", pat_name->s_name); - return; - } - pattern_setcell(pat, (t_int)rownum, (t_int)colnum, &argv[3]); -} - -static t_atom* track_proxy_getcell(t_track_proxy* x, t_symbol* pat_name, t_floatarg rownum, t_floatarg colnum) { - ArrayListGetByName(x->x_track->x_patterns, pat_name, t_pattern*, pat); - if(!pat) { - error("track: getcell: no such pattern: '%s'", pat_name->s_name); - return NULL; - } - return pattern_getcell(pat, (t_int)rownum, (t_int)colnum); -} - -static t_atom* track_proxy_getcell_with_header(t_track_proxy* x, t_symbol* pat_name, t_floatarg rownum, t_floatarg colnum) { - t_atom* cell = track_proxy_getcell(x, pat_name, rownum, colnum); - if(!cell) { - error("track: getcell: no such pattern: '%s'", pat_name->s_name); - return NULL; - } - SETSYMBOL(&response_cell[0], pat_name); - SETFLOAT(&response_cell[1], rownum); - SETFLOAT(&response_cell[2], colnum); - memcpy(&response_cell[3], cell, sizeof(t_atom)); - return &response_cell[0]; -} - -static void track_proxy_getcell_o(t_track_proxy* x, t_symbol* pat_name, t_floatarg rownum, t_floatarg colnum) { - t_atom* cell = track_proxy_getcell(x, pat_name, rownum, colnum); - if(cell) - outlet_list(x->outlet, &s_list, 1, cell); -} - -static t_pattern* track_proxy_addpattern(t_track_proxy* x, t_symbol* name, t_floatarg rows) { - return pattern_new(x->x_track, name, (t_int)rows); -} - -static int track_proxy_removepattern(t_track_proxy* x, t_symbol* name) { - ArrayListGetByName(x->x_track->x_patterns, name, t_pattern*, pat); - if(!pat) { - error("track: removepattern: no such pattern: '%s'", name->s_name); - return 0; //FAIL - } - pattern_free(pat); - return 1; //OK -} - -static t_pattern* track_proxy_resizepattern(t_track_proxy* x, t_symbol* name, t_floatarg rows) { - ArrayListGetByName(x->x_track->x_patterns, name, t_pattern*, pat); - if(!pat) { - error("track: resizepattern: no such pattern: '%s'", name->s_name); - return NULL; - } - pattern_resize(pat, (t_int)rows); - return pat; -} - -static t_pattern* track_proxy_renamepattern(t_track_proxy* x, t_symbol* name, t_symbol* newname) { - ArrayListGetByName(x->x_track->x_patterns, name, t_pattern*, pat); - if(!pat) { - error("track: renamepattern: no such pattern: '%s'", name->s_name); - return NULL; - } - pattern_rename(pat, newname); - return pat; -} - -static t_pattern* track_proxy_copypattern(t_track_proxy* x, t_symbol* src, t_symbol* dst) { - ArrayListGetByName(x->x_track->x_patterns, src, t_pattern*, pat); - if(!pat) { - error("track: copypattern: no such pattern: '%s'", src->s_name); - return NULL; - } - ArrayListGetByName(x->x_track->x_patterns, dst, t_pattern*, pat2); - if(pat2) { - error("track: copypattern: destination '%s' exists", pat2->x_name->s_name); - return NULL; - } - return pattern_clone(pat, dst); -} diff --git a/composer/window.tk b/composer/window.tk deleted file mode 100644 index 1b90732..0000000 --- a/composer/window.tk +++ /dev/null @@ -1,614 +0,0 @@ -# ------------------------------------------------------------------------ -# Copyright (c) 2009 Federico Ferri. -# For information on usage and redistribution, and for a DISCLAIMER OF ALL -# WARRANTIES, see the file, "LICENSE.txt," in this distribution. -# -# composer: a music composition framework for pure-data -# -# This program 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. -# -# See file LICENSE for further informations on licensing terms. -# -# This program 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 this program; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# Based on PureData by Miller Puckette and others. -# ------------------------------------------------------------------------ - -package require Tcl 8.5 -package require Tk 8.5 -package require Tktable 2.9 - -namespace eval pd::composer { - variable debug - variable w - array set w {} - variable songname - array set songname {} - variable trackname - array set trackname {} - variable currentpattern - array set currentpattern {} - variable length - array set length {} - variable columns - array set columns {} - variable patterns - array set patterns {} - variable tracks - array set tracks {} - - variable quirks_fix_int_floats 0 - variable symbolmap {empty {}} - # set to 1 until startup, for getting soon a pattern list - # affects the behavior of dispatcher::patterns branch - variable startup - array set startup {} - variable showpattern - array set showpattern {} - - proc debugPrint {args} { - variable debug - if {![info exists debug]} {set debug 0} - if {$debug} {puts stderr "composer-TCL: $args"} - } - - proc sendGui {what} { - debugPrint "sendGui $what" - catch {netsend $what} - lappend what \;\n - catch {pdsend $what} - catch {pd {*}$what} - } - - proc createPattern {id name len} { - debugPrint [info level 0] - variable length - variable patterns - - if {$name in $patterns($id)} { - return -code error "Pattern '$name' already exists" - } - set len [expr {int($len)}] - if {$len <= 0} { - return -code error "Length must be positive integer" - } - - sendGui [concat $id EDIT addpattern $name $len] - } - - proc removePattern {id name} { - debugPrint [info level 0] - variable length; - variable patterns; - - sendGui [concat $id EDIT removepattern $name] - } - - proc copyPattern {id src dst} { - debugPrint [info level 0] - variable length; - - sendGui [concat $id EDIT copypattern $src $dst] - } - - proc resizePattern {id name newSize} { - debugPrint [info level 0] - variable currentpattern; - variable length; - - if {$newSize == [dict get $length($id) $name]} return - - set len [expr {int($newSize)}] - if {$len <= 0} { - return -code error "Length must pe positive integer" - } - - sendGui [concat $id EDIT resizepattern $name $len] - } - - proc renamePattern {id name newName} { - debugPrint [info level 0] - variable length; - variable patterns; - - if {$name == $newName} return - if {$newName in $patterns($id)} { - return -code error "Pattern name '$newName' already exists" - } - set idx [lsearch -exact $patterns($id) $name] - if {$idx == -1} { - return -code error "No such pattern: '$name'" - } - - sendGui [concat $id EDIT renamepattern $name $newName] - } - - proc generateNewPatternName {id} { - debugPrint [info level 0] - variable patterns; - set n 0 - while 1 { - set t "P[format %.02d $n]" - if {$t in $patterns($id)} {incr n} else {return $t} - } - } - - proc displayPattern {id name} { - debugPrint "request-pattern-length" - variable showpattern - set showpattern($id) 1 - sendGui [concat $id EDIT getpatternlength $name] - } - - proc updateTitle {id} { - variable w - variable songname - variable trackname - variable currentpattern - set t "Song: $songname($id)" - if {$currentpattern($id) == "Arrangement"} { - append t " Arrangement" - } else { - append t " Track: $trackname($id)" - if {$currentpattern($id) != {}} { - append t " Pattern: $currentpattern($id)" - } - } - wm title $w($id) $t - } - - proc displayPattern_async {id name} { - debugPrint [info level 0] - variable currentpattern - variable patterns - variable length - variable columns - variable w - variable songname - variable trackname - variable [getDataVar $id] - - set currentpattern($id) $name - updateTitle $id - - if {$currentpattern($id) == {}} { - grid forget $w($id).t - return - } - - set rows [dict get $length($id) $name] - set cols $columns($id) - grid $w($id).t -row 10 -column 0 -sticky news - debugPrint "resizing tktable widget to ${rows}x${cols}" - $w($id).t configure -state normal -variable [getDataVar $id] -rows $rows -cols [expr {1+$cols}] - $w($id).f.p configure -values $patterns($id) - $w($id).f.p current [lsearch -exact $patterns($id) $name] - } - - proc displayCurrentPattern {id} { - debugPrint [info level 0] - variable currentpattern - variable w - debugPrint "current pattern is {$currentpattern($id)}" - displayPattern $id $currentpattern($id) - } - - proc rowTag {id r} { - if {$r % $::div1 == 0} {return "alt0"} - if {$r % $::div2 == 0} {return "alt1"} - } - - proc refreshGrid {id} { - debugPrint [info level 0] - variable currentpattern - debugPrint "currentPattern is {$currentpattern($id)}" - variable w - $w($id).t configure -padx [$w($id).t cget -padx] - } - - proc edit {id r c bwrite value} { - # NOT USED - #if {$bwrite} { - # sendGui [concat $id EDIT setcell $currentpattern($id) $r $c $value] - #} else { - #} - } - - proc getDataVar {id {P {}}} { - variable currentpattern - variable songname - variable trackname - if {$P == ""} {set P $currentpattern($id)} - set n "[namespace current]::data_$songname($id)_$trackname($id)_$P" - if {![info exists $n]} {array set $n {}} - return $n - } - - proc createMainWindow {id} { - debugPrint [info level 0] - variable currentpattern; - variable w - variable songname - variable trackname - variable patterns - variable startup - variable showpattern - variable [getDataVar $id] - - catch {destroy $w($id)} - debugPrint "creating window with path = '$w($id)'" - toplevel $w($id) - - debugPrint "top-toolbar(frame)" - grid [ttk::frame $w($id).f] \ - -row 5 -columnspan 2 -sticky news - debugPrint "label" - grid [ttk::label $w($id).f.l -text "Pattern: "] \ - -row 0 -column 0 -in $w($id).f - debugPrint "combobox patterns" - grid [ttk::combobox $w($id).f.p -textvariable "[namespace current]::currentpattern($id)"] \ - -row 0 -column 1 -in $w($id).f - debugPrint "divs" - grid [ttk::label $w($id).f.ld1 -text "Div1: "] \ - -row 0 -column 2 -in $w($id).f - grid [spinbox $w($id).f.d1 -command "[namespace current]::refreshGrid $id" -from 8 -to 64 \ - -increment 1 -format %3.0f -width 3 -textvar ::div1] \ - -row 0 -column 3 -in $w($id).f - grid [ttk::label $w($id).f.ld2 -text "Div2: "] \ - -row 0 -column 4 -in $w($id).f - grid [spinbox $w($id).f.d2 -command "[namespace current]::refreshGrid $id" -from 2 -to 64 \ - -increment 1 -format %3.0f -width 3 -textvar ::div2] \ - -row 0 -column 5 -in $w($id).f - - debugPrint "step2" - $w($id).f.p state readonly - - debugPrint "bindevent" - bind $w($id).f.p <> "[namespace current]::displayCurrentPattern $id" - debugPrint "table" - - table $w($id).t -state disabled \ - -insertofftime 0 \ - -bordercursor sb_h_double_arrow \ - -colorigin -1 -sparsearray 1 \ - -relief ridge -takefocus 1 -borderwidth 1 -colwidth 4 \ - -browsecmd "[namespace current]::activeCellChanges $id %r %c" \ - -cols 0 -rows 0 \ - -cache 0 \ - -usecommand 0 -command "[namespace current]::edit $id %r %c %i %s" \ - -colstretchmode none -rowstretchmode none \ - -flashmode 1 -flashtime 2 -autoclear 1 \ - -justify left -multiline 0 -resizeborders col \ - -selectmode extended -selecttype cell \ - -titlecols 1 -titlerows 0 -validate 1 \ - -validatecommand "[namespace current]::validateCommand $id %r %c %s %S" \ - -variable [getDataVar $id] -exportselection 1 \ - -xscrollcommand "$w($id).hscroll set" \ - -yscrollcommand "$w($id).vscroll set" \ - -rowtagcommand "[namespace current]::rowTag $id" - #grid $w($id).t -row 10 -column 0 -sticky news - - debugPrint "scrollbars" - grid [ttk::scrollbar $w($id).vscroll -orient vertical -command "$w($id).t yview"] -row 10 -column 1 -sticky ns - grid [ttk::scrollbar $w($id).hscroll -orient horizontal -command "$w($id).t xview"] -row 15 -column 0 -sticky ew - #grid [ttk::sizegrip $w($id).resize] -row 15 -column 1 -sticky se - - grid [ttk::entry $w($id).eval] -row 20 -columnspan 2 -sticky ew - bind $w($id).eval "set cmd \[$w($id).eval get]; namespace eval [namespace current] \$cmd; $w($id).eval delete 0 end" - - debugPrint "grid" - grid columnconfigure $w($id) 0 -weight 1 - grid rowconfigure $w($id) 10 -weight 1 - - debugPrint "table-tags" - $w($id).t tag configure active -relief solid -background gray -foreground black - $w($id).t tag configure flash -background red -foreground white - $w($id).t tag configure sel -background blue -foreground white - $w($id).t tag configure title -background gray -foreground white -justify right - $w($id).t tag configure alt0 -background "#20a8b8" - $w($id).t tag configure alt1 -background "#0f7f9f" - $w($id).t tag configure notecol -background "#dddded" - - debugPrint "wm" - wm minsize $w($id) 300 150 - wm protocol $w($id) WM_DELETE_WINDOW "[namespace current]::sendGui {$id EDIT editor-close}" - - debugPrint "menu" - menu $w($id).m -tearoff 0 - $w($id).m add command -label "New pattern..." \ - -command "[namespace current]::newPatternDialog $id" - $w($id).m add command -label "Pattern properties..." \ - -command "[namespace current]::patternPropertiesDialog $id" - $w($id).m add command -label "Remove pattern..." \ - -command "[namespace current]::removePatternConfirm $id" - $w($id).m add command -label "Create copy..." \ - -command "[namespace current]::copyPatternDialog $id" - - menu $w($id).mb - $w($id) configure -menu $w($id).mb - menu $w($id).mb.tools -tearoff 0 - $w($id).mb.tools add command -label {Reload} \ - -command {uplevel 0 {source $argv0}} - $w($id).mb add cascade -label {Pattern} -menu $w($id).m - $w($id).mb add cascade -label {Utils} -menu $w($id).mb.tools - - debugPrint "more-bind-events" - bind $w($id).t "$w($id).t activate @%x,%y; tk_popup $w($id).m %X %Y" - bind $w($id).t "switchColumnType $id" - - set startup($id) 1 - set showpattern($id) 0 - debugPrint "request-patterns" - sendGui [concat $id EDIT getpatterns] - sendGui [concat $id EDIT gettracks] - - return $w($id) - } - - proc switchColumnType {id} { - debugPrint [info level 0] - variable w - global colType - set curcol [$w($id).t index active col] - set tag {} - if {![info exists colType(c$curcol)]} { - set colType(c$curcol) {notes} - set tag {notecol} - } elseif {$colType(c$curcol) == {notes}} { - unset colType(c$curcol) - } - - $w($id).t tag col $tag $curcol - #refreshGrid - } - - proc activeCellChanges {id row col} { - debugPrint [info level 0] - variable w - if {$col < 0} {$w($id).t activate $row,[incr col]} - } - - proc validateCommand {id row col curVal newVal} { - debugPrint [info level 0] - variable currentpattern - variable symbolmap - - debugPrint "BEFORE: newVal = '$newVal'" - set newVal [dict get [dict merge [list $newVal $newVal] [lreverse $symbolmap]] $newVal] - debugPrint "AFTER: newVal = '$newVal'" - - sendGui [concat $id EDIT setcell $currentpattern($id) $row $col $newVal] - - return 1 - } - - proc patternPropertiesDialog_common {id options} { - debugPrint [info level 0] - variable currentpattern - variable w - set bname 1 - set blength 1 - set old_name {} - catch {set old_name $currentpattern($id)} - set vname {} - set vlength {} - set action_cancel {destroy %w} - set action_ok $action_cancel - - set opts {vname vlength bname blength action_ok action_cancel} - foreach opt $opts { - catch {set $opt [dict get $options $opt]} - } - foreach {o v} $options { - if {$o ni $opts} { - return -code error "Invalid option: $o" - } - } - - set w_ $w($id).patternProps - catch {destroy $w_} - toplevel $w_ - - foreach v {action_ok action_cancel} { - set $v [string map [list %ns [namespace current] %id $id %w $w_ %old_name $old_name] [set $v]] - } - - grid [ttk::label $w_.lname -text "Name: "] -row 0 -column 0 - grid [ttk::label $w_.llength -text "Rows: "] -row 1 -column 0 - grid [ttk::entry $w_.ename] -row 0 -column 1 - grid [ttk::entry $w_.elength] -row 1 -column 1 - grid [ttk::frame $w_.b] -row 2 -columnspan 2 - grid [ttk::button $w_.b.ok -text Ok -command $action_ok] -row 0 -column 0 -in $w_.b - grid [ttk::button $w_.b.cancel -text Cancel -command $action_cancel] -row 0 -column 1 -in $w_.b - - $w_.ename insert 0 $vname - $w_.elength insert 0 $vlength - - if {!$bname} {$w_.ename configure -state disabled} - if {!$blength} {$w_.elength configure -state disabled} - } - - proc patternPropertiesDialog {id {options {}}} { - debugPrint [info level 0] - variable currentpattern; - variable length; - - dict set options action_ok { - %ns::resizePattern %id %old_name [%w.elength get] - %ns::renamePattern %id %old_name [%w.ename get] - destroy %w - } - dict set options vname $currentpattern($id) - dict set options vlength [dict get $length($id) $currentpattern($id)] - patternPropertiesDialog_common $id $options - } - - proc copyPatternDialog {id {options {}}} { - debugPrint [info level 0] - variable w; - variable length; - - dict set options blength 0 - dict set options vname [generateNewPatternName $id] - dict set options vlength [dict get $length($id) $currentpattern($id)] - dict set options action_ok { - %ns::copyPattern %id %old_name [%w.ename get] - destroy %w - } - patternPropertiesDialog_common $id $options - } - - proc removePatternConfirm {id} { - debugPrint [info level 0] - variable currentpattern; - if {[tk_messageBox \ - -type yesno -default no \ - -title "Question" \ - -icon question -message "Do you confirm pattern delete?" \ - -detail "The operation cannot be undone" \ - -parent $w] == {yes}} { - removePattern $id $currentpattern($id) - } - } - - proc newPatternDialog {id {options {}}} { - debugPrint [info level 0] - dict set options action_ok { - %ns::createPattern %id [%w.ename get] [%w.elength get] - destroy %w - } - dict set options vname [generateNewPatternName $id] - dict set options vlength 16 - patternPropertiesDialog_common $id $options - } - - #entrypoint - proc init {id song_name track_name cols set_current_pattern debug_flag} { - debugPrint [info level 0] - variable debug - set debug [expr {$debug_flag != 0}] - variable w - variable songname - variable trackname - variable length - variable currentpattern - variable columns - set w($id) .w_${song_name}_${track_name} - set songname($id) $song_name - set trackname($id) $track_name - if {$set_current_pattern == {NULL}} { - set currentpattern($id) {} - } else { - set currentpattern($id) $set_current_pattern - } - set length($id) {} - set columns($id) $cols - } - - proc openWindow {id} { - debugPrint [info level 0] - createMainWindow $id - } - - proc closeWindow {id} { - debugPrint [info level 0] - variable w - destroy $w($id) - } - - proc setCellValueUI {id pat r c v} { - upvar 0 [getDataVar $id $pat] data - variable symbolmap - set data($r,$c) [dict get [dict merge [list $v $v] $symbolmap] $v] - } - - proc dispatch {id args} { - debugPrint [info level 0] - variable w - variable patterns - variable length - variable currentpattern - variable startup - variable showpattern - variable columns - variable quirks_fix_int_floats - switch -exact [lindex $args 0] { - patterns { - # for track mode - set patterns($id) [lrange $args 1 end] - debugPrint "patterns <- $patterns($id)" - $w($id).f.p configure -values $patterns($id) - if {$startup($id)} { - set startup($id) 0 - if {[llength $patterns($id)] > 0} { - displayPattern $id [lindex $patterns($id) 0] - } - } - } - tracks { - # for song mode - set tracks($id) [lrange $args 1 end] - debugPrint "tracks <- $tracks($id)" - set cols [llength $tracks($id)] - #debugPrint "resizing tktable widget to ${cols} cols" - #$w($id).t configure -state normal -cols $cols - set columns($id) $cols - } - patternlength { - set pat_name [lindex $args 1] - set pat_length [lindex $args 2] - debugPrint "got patternlength: '$pat_name' (len=$pat_length)" - if {![dict exists $length($id) $pat_name] || [dict get $length($id) $pat_name] != $pat_length || $showpattern($id)} { - dict set length($id) $pat_name $pat_length - for {set i 0} {$i < $pat_length} {incr i} { - sendGui [concat $id EDIT getrow $pat_name $i] - } - } - } - row { - set pat_name [lindex $args 1] - if {$quirks_fix_int_floats} { - set row_num [expr {int([lindex $args 2])}] - } else { - set row_num [lindex $args 2] - } - set row [lrange $args 3 end] - debugPrint "got row: '$pat_name' ($row_num) {$row}" - setCellValueUI $id $pat_name $row_num -1 [expr {1+$row_num}] - for {set i 0} {$i < [llength $row]} {incr i} { - setCellValueUI $id $pat_name $row_num $i [lindex $row $i] - } - if {$row_num + 1 == [dict get $length($id) $pat_name]} { - if {$showpattern($id)} { - set showpattern($id) 0 - displayPattern_async $id $pat_name - } - } - } - cell { - set pat_name [lindex $args 1] - if {$quirks_fix_int_floats} { - set row_num [expr {int([lindex $args 2])}] - set col_num [expr {int([lindex $args 3])}] - } else { - set row_num [lindex $args 2] - set col_num [lindex $args 3] - } - set cell [lindex $args 4] - debugPrint "got cell: '$pat_name' ($row_num,$col_num) {$cell}" - debugPrint "dataVar = [getDataVar $id $pat_name]" - setCellValueUI $id $pat_name $row_num $col_num $cell - } - } - } -} -- cgit v1.2.1