diff options
Diffstat (limited to 'synth')
-rw-r--r-- | synth/Makefile | 2 | ||||
-rw-r--r-- | synth/cli.cpp | 6 | ||||
-rw-r--r-- | synth/globals.cpp | 1 | ||||
-rw-r--r-- | synth/globals.h | 1 | ||||
-rw-r--r-- | synth/in_synth_cli.cpp | 37 | ||||
-rw-r--r-- | synth/in_synth_cli.h | 8 | ||||
-rw-r--r-- | synth/main.cpp | 32 | ||||
-rw-r--r-- | synth/watch_files.cpp | 160 | ||||
-rw-r--r-- | synth/watch_files.h | 9 |
9 files changed, 253 insertions, 3 deletions
diff --git a/synth/Makefile b/synth/Makefile index a9ec0a1..39b6e80 100644 --- a/synth/Makefile +++ b/synth/Makefile @@ -3,7 +3,7 @@ CFLAGS=-Wall -O2 -g CXXFLAGS=$(CFLAGS) LDFLAGS=-lm `pkg-config --cflags --libs jack` -OBJ=channel.o cli.o defines.o envelope.o filter.o globals.o jack.o load.o main.o note.o note_skel.o parser.o programs.o readwave.o util.o note_loader.o in_synth_cli.o communication.o shared_object_manager.o lfos.o +OBJ=channel.o cli.o defines.o envelope.o filter.o globals.o jack.o load.o main.o note.o note_skel.o parser.o programs.o readwave.o util.o note_loader.o in_synth_cli.o communication.o shared_object_manager.o lfos.o watch_files.o BIN=synth DEPENDFILE = .depend diff --git a/synth/cli.cpp b/synth/cli.cpp index eb52c95..4d5cc2f 100644 --- a/synth/cli.cpp +++ b/synth/cli.cpp @@ -30,6 +30,8 @@ void parse_args(int argc, char** argv) {"xruns", required_argument, 0, 'x'}, {"dir", required_argument, 0, 'd'}, {"directory", required_argument, 0, 'd'}, + {"no-watch-files", no_argument, 0, 'w'}, + {"dont-watch-files", no_argument, 0, 'w'}, {"program", required_argument, 0, 'p'}, {"cleanup-interval", required_argument, 0, 'i'}, {"lfo0-freq", required_argument, 0, 400}, //FINDLFO @@ -59,7 +61,7 @@ void parse_args(int argc, char** argv) while (optind<argc) { int index=-1; - int result=getopt_long(argc,argv,"hVf:d:p:i:c:x:vqFam", long_options, &index); + int result=getopt_long(argc,argv,"hVf:d:p:i:c:x:vqFamw", long_options, &index); if (result==-1) break; switch (result) @@ -131,6 +133,8 @@ void parse_args(int argc, char** argv) else output_warning("WARNING: not a number in --interval option. ignoring it..."); break; + case 'w': watchfiles=false; + break; case 304: if (isfloat(optarg)) snh_freq_hz=atof(optarg); else diff --git a/synth/globals.cpp b/synth/globals.cpp index 96a56d5..8cde306 100644 --- a/synth/globals.cpp +++ b/synth/globals.cpp @@ -18,6 +18,7 @@ bool quiet=false; bool connect_audio=true, connect_midi=true; +bool watchfiles=true; float cleanup_interval_sec=0; float snh_freq_hz=0; diff --git a/synth/globals.h b/synth/globals.h index b89813d..bccacdf 100644 --- a/synth/globals.h +++ b/synth/globals.h @@ -29,6 +29,7 @@ extern bool quiet; extern bool connect_audio, connect_midi; +extern bool watchfiles; extern float cleanup_interval_sec; extern float snh_freq_hz; diff --git a/synth/in_synth_cli.cpp b/synth/in_synth_cli.cpp index 7ca9c7d..fc24b03 100644 --- a/synth/in_synth_cli.cpp +++ b/synth/in_synth_cli.cpp @@ -10,11 +10,14 @@ #include "globals.h" #include "load.h" #include "lfos.h" +#include "watch_files.h" using namespace std; #define PROMPT "> " +pthread_mutex_t prog_load_mutex; + void signal_handler(int sig) { cout << endl << PROMPT << flush; @@ -49,12 +52,18 @@ void do_request(int prg_no, bool susp) void lock_and_load_program(int prg_no, string file) { + pthread_mutex_lock(&prog_load_mutex); + + remove_watch(prg_no); + do_request(prg_no, true); if (load_program(file,program_settings[prg_no])) { cout << "success" << endl; programfile[prg_no]=file; + + add_watch(prg_no); } else cout << "failed" << endl; @@ -63,6 +72,32 @@ void lock_and_load_program(int prg_no, string file) channel[i]->maybe_reload_program(prg_no); do_request(prg_no, false); + + pthread_mutex_unlock(&prog_load_mutex); +} + +//only use this, if you don't want the file-watches to be updated +//i.e., only when reloading a program! +void lock_and_load_program_no_watch_updates(int prg_no, string file) +{ + pthread_mutex_lock(&prog_load_mutex); + + do_request(prg_no, true); + + if (load_program(file,program_settings[prg_no])) + { + cout << "success" << endl; + programfile[prg_no]=file; + } + else + cout << "failed" << endl; + + for (int i=0;i<N_CHANNELS;++i) + channel[i]->maybe_reload_program(prg_no); + + do_request(prg_no, false); + + pthread_mutex_unlock(&prog_load_mutex); } void lock_and_change_lfo(int lfo_no, float freq) @@ -83,6 +118,8 @@ void do_in_synth_cli() string command; string params; int num; + + pthread_mutex_init(&prog_load_mutex, NULL); if (signal(2,signal_handler)==SIG_ERR) output_warning("WARNING: failed to set signal handler in the in-synth-cli. pressing ctrl+c will\n" diff --git a/synth/in_synth_cli.h b/synth/in_synth_cli.h index 27ae216..18f7a62 100644 --- a/synth/in_synth_cli.h +++ b/synth/in_synth_cli.h @@ -1,6 +1,14 @@ #ifndef __IN_SYNTH_CLI_H__ #define __IN_SYNTH_CLI_H__ +#include <string> + +using namespace std; + void do_in_synth_cli(); + +//only use this, if you don't want the file-watches to be updated +//i.e., only when reloading a program! +void lock_and_load_program_no_watch_updates(int prg_no, string file); #endif diff --git a/synth/main.cpp b/synth/main.cpp index a9d7ef0..32b2b84 100644 --- a/synth/main.cpp +++ b/synth/main.cpp @@ -2,6 +2,7 @@ #include <iostream> #include <cmath> #include <cstdlib> +#include <pthread.h> #include "jack.h" #include "load.h" @@ -15,6 +16,7 @@ #include "communication.h" #include "note_loader.h" #include "lfos.h" +#include "watch_files.h" using namespace std; @@ -22,9 +24,10 @@ using namespace std; void cleanup(); void dump_options(); +pthread_t watcher_thread=-1; int main(int argc, char** argv) -{ +{ init_communication(); for (int i=0;i<N_LFOS;++i) @@ -118,6 +121,21 @@ int main(int argc, char** argv) start_jack(connect_audio, connect_midi); + if (watchfiles) + { + if (pthread_create(&watcher_thread, NULL, watch_files, NULL) != 0) + { + output_warning("WARNING: could not start file-watcher thread. you must inform me about\n" + " updated files manually."); + watcher_thread=-1; + } + } + else + { + output_note("NOTE: you disabled the watching of files. you must inform me about\n" + " updated files manually."); + } + do_in_synth_cli(); cleanup(); @@ -135,6 +153,18 @@ int main(int argc, char** argv) void cleanup() { + if (watcher_thread!=-1) + { + if (pthread_cancel(watcher_thread) != 0) + { + output_warning("WARNING: could not cancel watcher thread!"); + } + else + { + pthread_join(watcher_thread,NULL); + } + } + exit_jack(); uninit_communication(); diff --git a/synth/watch_files.cpp b/synth/watch_files.cpp new file mode 100644 index 0000000..ce80224 --- /dev/null +++ b/synth/watch_files.cpp @@ -0,0 +1,160 @@ +#include <iostream> +#include <pthread.h> +#include <unistd.h> +#include <sys/inotify.h> + +#include "watch_files.h" +#include "util.h" +#include "globals.h" +#include "in_synth_cli.h" + +using namespace std; + +int fd=-1; +map<int, set<int> > inotify_map; +pthread_mutex_t inotify_map_mutex; + +void watch_files_cleanup(void* unused) +{ + if (fd==-1) + { + output_verbose("NOTE: no cleaning necessary for watch-files-thread"); + } + else + { + output_verbose("NOTE: cleaning up for watch-files-thread..."); + + } +} + +void* watch_files(void* unused) +{ + pthread_cleanup_push(watch_files_cleanup, NULL); + + pthread_mutex_init(&inotify_map_mutex, NULL); + + fd=inotify_init(); + if (fd==-1) + { + output_warning("WARNING: could not initalize inotify. you must inform me about\n" + " updated files manually."); + while (true) sleep(10); + } + else + { + for (int i=0;i<128;i++) // add watches for all loaded programs + if (programfile[i]!="") + add_watch(i); + + inotify_event ev; + size_t s; + while (true) + { + s=read (fd, &ev, sizeof(inotify_event)); + while (s<sizeof(inotify_event)) + s+=read (fd,(char*)&ev + s, sizeof(inotify_event)-s); + + pthread_mutex_lock(&inotify_map_mutex); + + if (ev.mask & IN_MODIFY) + { + if (verbose) + { + string str=""; + set<int>& tmp=inotify_map[ev.wd]; + for (set<int>::iterator it=tmp.begin(); it!=tmp.end(); it++) + str+="#"+IntToStr(*it)+" "; + + output_verbose("NOTE: reloading programs "+str+"..."); + } + + set<int>& tmp=inotify_map[ev.wd]; + for (set<int>::iterator it=tmp.begin(); it!=tmp.end(); it++) + lock_and_load_program_no_watch_updates(*it, programfile[*it]); + } + else if (ev.mask & (IN_MOVE_SELF | IN_DELETE_SELF)) + { + if (verbose) + { + string str=""; + set<int>& tmp=inotify_map[ev.wd]; + for (set<int>::iterator it=tmp.begin(); it!=tmp.end(); it++) + str+="#"+IntToStr(*it)+" "; + + output_verbose("NOTE: removed watch for programs "+str); + } + + inotify_map.erase(ev.wd); + inotify_rm_watch(fd,ev.wd); + } + else if (ev.mask != IN_IGNORED) + { + output_note("NOTE: in watch_files-thread: unknown event received ("+IntToStrHex(ev.mask)+")"); + } + + pthread_mutex_unlock(&inotify_map_mutex); + } + } + + pthread_cleanup_pop(0); +} + +void remove_watch(int prog) +{ + if (watchfiles) + { + map<int, set<int> >::iterator mit; + set<int>* tmp; + set<int>::iterator sit; + + pthread_mutex_lock(&inotify_map_mutex); + + //search in all known watch descriptors + for (mit=inotify_map.begin(); mit!=inotify_map.end(); mit++) + { + tmp=&(mit->second); + sit=tmp->find(prog); + + //search for some wd which affects $prog + if (sit!=tmp->end()) //found? + { + //erase $prog from the affect-set + tmp->erase(sit); + if (tmp->empty()) + { + //if the affect-set is now empty, we can garbage-collect + //the wd (i.e., remove it) + cout << "garbage collecting wd #"<<mit->first<<endl; + inotify_rm_watch(fd, mit->first); + inotify_map.erase(mit); + } + + //we're done now + break; + } + } + + pthread_mutex_unlock(&inotify_map_mutex); + } +} + +void add_watch(int prog) +{ + if (watchfiles) + { + int wd=inotify_add_watch(fd, programfile[prog].c_str(), IN_MODIFY | IN_MOVE_SELF | IN_DELETE_SELF); + + pthread_mutex_lock(&inotify_map_mutex); + + if (wd!=-1) + { + inotify_map[wd].insert(prog); + } + else + { + //TODO: warning + } + + pthread_mutex_unlock(&inotify_map_mutex); + } +} diff --git a/synth/watch_files.h b/synth/watch_files.h new file mode 100644 index 0000000..b9c7d2d --- /dev/null +++ b/synth/watch_files.h @@ -0,0 +1,9 @@ +#ifndef __WATCH_FILES_H__ +#define __WATCH_FILES_H__ + +void* watch_files(void* unused); + +void add_watch(int prog); +void remove_watch(int prog); + +#endif |