/[svn]/gigedit/trunk/src/gigedit/gigedit.cpp
ViewVC logotype

Annotation of /gigedit/trunk/src/gigedit/gigedit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1654 - (hide annotations) (download)
Wed Jan 30 02:20:48 2008 UTC (16 years, 2 months ago) by schoenebeck
File size: 8525 byte(s)
* first step to make the virtual keyboard interactive: active keys of the
  sampler (in live-mode only of course) are highlighted on the virtual
  keyboard - NOTE: yet inaccurate draw of the keys and this mechanism
  yet only works on the first gigedit invocation by the sampler process,
  so this still has to be fixed

1 schoenebeck 1225 /*
2 schoenebeck 1654 * Copyright (C) 2007, 2008 Andreas Persson
3 schoenebeck 1225 *
4     * This program is free software; you can redistribute it and/or
5     * modify it under the terms of the GNU General Public License as
6     * published by the Free Software Foundation; either version 2, or (at
7     * your option) any later version.
8     *
9     * This program is distributed in the hope that it will be useful, but
10     * WITHOUT ANY WARRANTY; without even the implied warranty of
11     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12     * General Public License for more details.
13     *
14     * You should have received a copy of the GNU General Public License
15     * along with program; see the file COPYING. If not, write to the Free
16     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17     * 02110-1301 USA.
18     */
19    
20     #include "gigedit.h"
21    
22     #include <gtkmm/main.h>
23 schoenebeck 1654 #include <glibmm/main.h>
24 schoenebeck 1225 #include "mainwindow.h"
25    
26 schoenebeck 1396 #include "global.h"
27 schoenebeck 1225
28 schoenebeck 1654 GigEditJob::GigEditJob() {
29     _msecs = 100; // 100ms by default
30     }
31    
32     int GigEditJob::msecs() {
33     return _msecs;
34     }
35    
36 persson 1456 namespace {
37 schoenebeck 1225
38 persson 1456 // State for a gigedit thread.
39     //
40     // This class is only used when gigedit is run as a plugin and makes
41     // sure that there's only one Gtk::Main event loop. The event loop is
42     // started in a separate thread. The plugin thread just dispatches an
43     // event to the main loop to open a window and then goes to sleep
44     // until the window is closed.
45     //
46     class GigEditState : public sigc::trackable {
47     public:
48     GigEditState(GigEdit* parent) : parent(parent) { }
49     void run(gig::Instrument* pInstrument);
50    
51 schoenebeck 1654 static std::vector< GigEditJob* > timeoutJobs;
52     MainWindow* window;
53    
54 persson 1456 private:
55    
56     // simple condition variable abstraction
57     class Cond {
58     private:
59     bool pred;
60     Glib::Mutex mutex;
61     Glib::Cond cond;
62     public:
63     Cond() : pred(false) { }
64     void signal() {
65     Glib::Mutex::Lock lock(mutex);
66     pred = true;
67     cond.signal();
68     }
69     void wait() {
70     Glib::Mutex::Lock lock(mutex);
71     while (!pred) cond.wait(mutex);
72     }
73     };
74    
75     static Glib::StaticMutex mutex;
76     static Glib::Dispatcher* dispatcher;
77     static GigEditState* current;
78    
79     static void main_loop_run(Cond* intialized);
80     static void open_window_static();
81    
82     GigEdit* parent;
83     Cond open;
84     Cond close;
85     gig::Instrument* instrument;
86    
87     void open_window();
88     void close_window();
89     };
90    
91     void init_app() {
92 schoenebeck 1333 static bool process_initialized = false;
93     if (!process_initialized) {
94     std::cout << "Initializing 3rd party services needed by gigedit.\n"
95     << std::flush;
96     setlocale(LC_ALL, "");
97 schoenebeck 1396
98     #if HAVE_GETTEXT
99 schoenebeck 1333 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
100     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
101     textdomain(GETTEXT_PACKAGE);
102 schoenebeck 1396 #endif // HAVE_GETTEXT
103    
104 schoenebeck 1333 // make sure thread_init() is called once and ONLY once per process
105     if (!Glib::thread_supported()) Glib::thread_init();
106    
107     process_initialized = true;
108     }
109 schoenebeck 1225 }
110    
111 persson 1456 void connect_signals(GigEdit* gigedit, MainWindow* mainwindow) {
112 schoenebeck 1322 // the signals of the "GigEdit" class are actually just proxies, that
113     // is they simply forward the signals of the internal classes to the
114     // outer world
115     mainwindow->signal_file_structure_to_be_changed().connect(
116     gigedit->signal_file_structure_to_be_changed().make_slot()
117     );
118     mainwindow->signal_file_structure_changed().connect(
119     gigedit->signal_file_structure_changed().make_slot()
120     );
121     mainwindow->signal_samples_to_be_removed().connect(
122     gigedit->signal_samples_to_be_removed().make_slot()
123     );
124     mainwindow->signal_samples_removed().connect(
125     gigedit->signal_samples_removed().make_slot()
126     );
127     mainwindow->signal_region_to_be_changed().connect(
128     gigedit->signal_region_to_be_changed().make_slot()
129     );
130     mainwindow->signal_region_changed().connect(
131     gigedit->signal_region_changed().make_slot()
132     );
133     mainwindow->signal_dimreg_to_be_changed().connect(
134     gigedit->signal_dimreg_to_be_changed().make_slot()
135     );
136     mainwindow->signal_dimreg_changed().connect(
137     gigedit->signal_dimreg_changed().make_slot()
138     );
139     mainwindow->signal_sample_ref_changed().connect(
140     gigedit->signal_sample_ref_changed().make_slot()
141     );
142     }
143    
144 schoenebeck 1654 } // namespace
145    
146     GigEdit::GigEdit() {
147     state = NULL;
148 schoenebeck 1225 }
149    
150 persson 1456 int GigEdit::run(int argc, char* argv[]) {
151     init_app();
152    
153     Gtk::Main kit(argc, argv);
154 schoenebeck 1225 MainWindow window;
155 persson 1456 connect_signals(this, &window);
156     if (argc >= 2) window.load_file(argv[1]);
157 schoenebeck 1225 kit.run(window);
158     return 0;
159     }
160    
161     int GigEdit::run(gig::Instrument* pInstrument) {
162 persson 1456 init_app();
163    
164     GigEditState state(this);
165 schoenebeck 1654 this->state = &state;
166 persson 1456 state.run(pInstrument);
167 schoenebeck 1654 this->state = NULL;
168 schoenebeck 1225 return 0;
169     }
170 schoenebeck 1322
171 schoenebeck 1654 void GigEdit::add_timeout_job(GigEditJob* job) {
172     GigEditState::timeoutJobs.push_back(job);
173     }
174    
175     void GigEdit::on_note_on_event(int key, int velocity) {
176     if (!this->state) return;
177     GigEditState* state = (GigEditState*) this->state;
178     state->window->signal_note_on().emit(key, velocity);
179     }
180    
181     void GigEdit::on_note_off_event(int key, int velocity) {
182     if (!this->state) return;
183     GigEditState* state = (GigEditState*) this->state;
184     state->window->signal_note_off().emit(key, velocity);
185     }
186    
187 schoenebeck 1339 sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_to_be_changed() {
188 schoenebeck 1322 return file_structure_to_be_changed_signal;
189     }
190    
191 schoenebeck 1339 sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_changed() {
192 schoenebeck 1322 return file_structure_changed_signal;
193     }
194    
195 schoenebeck 1339 sigc::signal<void, std::list<gig::Sample*> >& GigEdit::signal_samples_to_be_removed() {
196 schoenebeck 1322 return samples_to_be_removed_signal;
197     }
198    
199 schoenebeck 1339 sigc::signal<void>& GigEdit::signal_samples_removed() {
200 schoenebeck 1322 return samples_removed_signal;
201     }
202    
203 schoenebeck 1339 sigc::signal<void, gig::Region*>& GigEdit::signal_region_to_be_changed() {
204 schoenebeck 1322 return region_to_be_changed_signal;
205     }
206    
207 schoenebeck 1339 sigc::signal<void, gig::Region*>& GigEdit::signal_region_changed() {
208 schoenebeck 1322 return region_changed_signal;
209     }
210    
211 schoenebeck 1339 sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_to_be_changed() {
212 schoenebeck 1322 return dimreg_to_be_changed_signal;
213     }
214    
215 schoenebeck 1339 sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_changed() {
216 schoenebeck 1322 return dimreg_changed_signal;
217     }
218    
219 schoenebeck 1339 sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& GigEdit::signal_sample_ref_changed() {
220 schoenebeck 1322 return sample_ref_changed_signal;
221     }
222 persson 1456
223    
224     Glib::StaticMutex GigEditState::mutex = GLIBMM_STATIC_MUTEX_INIT;
225     Glib::Dispatcher* GigEditState::dispatcher = 0;
226     GigEditState* GigEditState::current = 0;
227 schoenebeck 1654 std::vector<GigEditJob*> GigEditState::timeoutJobs;
228 persson 1456
229     void GigEditState::open_window_static() {
230     GigEditState* c = GigEditState::current;
231     c->open.signal();
232     c->open_window();
233     }
234    
235     void GigEditState::open_window() {
236     window = new MainWindow();
237    
238     connect_signals(parent, window);
239     if (instrument) window->load_instrument(instrument);
240    
241     window->signal_hide().connect(sigc::mem_fun(this,
242     &GigEditState::close_window));
243     window->present();
244     }
245    
246     void GigEditState::close_window() {
247     delete window;
248     close.signal();
249     }
250    
251     void GigEditState::main_loop_run(Cond* initialized) {
252     int argc = 1;
253     const char* argv_c[] = { "gigedit" };
254     char** argv = const_cast<char**>(argv_c);
255     Gtk::Main main_loop(argc, argv);
256    
257     dispatcher = new Glib::Dispatcher();
258     dispatcher->connect(sigc::ptr_fun(&GigEditState::open_window_static));
259     initialized->signal();
260    
261 schoenebeck 1654 for (int i = 0; i < GigEditState::timeoutJobs.size(); i++) {
262     GigEditJob* job = timeoutJobs[i];
263     const Glib::RefPtr<Glib::TimeoutSource> timeout_source =
264     Glib::TimeoutSource::create(job->msecs());
265     timeout_source->connect(
266     sigc::mem_fun(*job, &GigEditJob::runGigEditJob)
267     );
268     timeout_source->attach(Glib::MainContext::get_default());
269     }
270    
271 persson 1456 main_loop.run();
272     }
273    
274     void GigEditState::run(gig::Instrument* pInstrument) {
275     mutex.lock(); // lock access to static variables
276    
277     static bool main_loop_started = false;
278     if (!main_loop_started) {
279     Cond initialized;
280     Glib::Thread::create(
281     sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
282     &initialized),
283     false);
284     initialized.wait();
285     main_loop_started = true;
286     }
287     instrument = pInstrument;
288     current = this;
289     dispatcher->emit();
290     open.wait(); // wait until the GUI thread has read current
291     mutex.unlock();
292     close.wait(); // sleep until window is closed
293     }

  ViewVC Help
Powered by ViewVC