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

Contents of /gigedit/trunk/src/gigedit/gigedit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1654 - (show 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 /*
2 * Copyright (C) 2007, 2008 Andreas Persson
3 *
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 #include <glibmm/main.h>
24 #include "mainwindow.h"
25
26 #include "global.h"
27
28 GigEditJob::GigEditJob() {
29 _msecs = 100; // 100ms by default
30 }
31
32 int GigEditJob::msecs() {
33 return _msecs;
34 }
35
36 namespace {
37
38 // 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 static std::vector< GigEditJob* > timeoutJobs;
52 MainWindow* window;
53
54 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 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
98 #if HAVE_GETTEXT
99 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
100 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
101 textdomain(GETTEXT_PACKAGE);
102 #endif // HAVE_GETTEXT
103
104 // 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 }
110
111 void connect_signals(GigEdit* gigedit, MainWindow* mainwindow) {
112 // 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 } // namespace
145
146 GigEdit::GigEdit() {
147 state = NULL;
148 }
149
150 int GigEdit::run(int argc, char* argv[]) {
151 init_app();
152
153 Gtk::Main kit(argc, argv);
154 MainWindow window;
155 connect_signals(this, &window);
156 if (argc >= 2) window.load_file(argv[1]);
157 kit.run(window);
158 return 0;
159 }
160
161 int GigEdit::run(gig::Instrument* pInstrument) {
162 init_app();
163
164 GigEditState state(this);
165 this->state = &state;
166 state.run(pInstrument);
167 this->state = NULL;
168 return 0;
169 }
170
171 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 sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_to_be_changed() {
188 return file_structure_to_be_changed_signal;
189 }
190
191 sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_changed() {
192 return file_structure_changed_signal;
193 }
194
195 sigc::signal<void, std::list<gig::Sample*> >& GigEdit::signal_samples_to_be_removed() {
196 return samples_to_be_removed_signal;
197 }
198
199 sigc::signal<void>& GigEdit::signal_samples_removed() {
200 return samples_removed_signal;
201 }
202
203 sigc::signal<void, gig::Region*>& GigEdit::signal_region_to_be_changed() {
204 return region_to_be_changed_signal;
205 }
206
207 sigc::signal<void, gig::Region*>& GigEdit::signal_region_changed() {
208 return region_changed_signal;
209 }
210
211 sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_to_be_changed() {
212 return dimreg_to_be_changed_signal;
213 }
214
215 sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_changed() {
216 return dimreg_changed_signal;
217 }
218
219 sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& GigEdit::signal_sample_ref_changed() {
220 return sample_ref_changed_signal;
221 }
222
223
224 Glib::StaticMutex GigEditState::mutex = GLIBMM_STATIC_MUTEX_INIT;
225 Glib::Dispatcher* GigEditState::dispatcher = 0;
226 GigEditState* GigEditState::current = 0;
227 std::vector<GigEditJob*> GigEditState::timeoutJobs;
228
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 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 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