/[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 1656 - (hide annotations) (download)
Sat Feb 2 08:18:19 2008 UTC (16 years, 1 month ago) by schoenebeck
File size: 7804 byte(s)
* bugfix: key highlighting of active keys on the virtual keyboard is now
  working on multiple invocations from the sampler as well
* renamed misleading names regarding the gig format's "keyswitching"
  feature (the dimension is now displayed as "keyswitching" instead of
  "keyboard" in the dimregchooser widget and the two parameters for
  defining the actual keyswitching area on the keyboard in the instruments
  properties dialog are now called "Keyswitching range low/high" instead of
  "Dimension key range low/high")

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 persson 1456 namespace {
29 schoenebeck 1225
30 persson 1456 // State for a gigedit thread.
31     //
32     // This class is only used when gigedit is run as a plugin and makes
33     // sure that there's only one Gtk::Main event loop. The event loop is
34     // started in a separate thread. The plugin thread just dispatches an
35     // event to the main loop to open a window and then goes to sleep
36     // until the window is closed.
37     //
38     class GigEditState : public sigc::trackable {
39     public:
40     GigEditState(GigEdit* parent) : parent(parent) { }
41     void run(gig::Instrument* pInstrument);
42    
43 schoenebeck 1654 MainWindow* window;
44    
45 persson 1456 private:
46    
47     // simple condition variable abstraction
48     class Cond {
49     private:
50     bool pred;
51     Glib::Mutex mutex;
52     Glib::Cond cond;
53     public:
54     Cond() : pred(false) { }
55     void signal() {
56     Glib::Mutex::Lock lock(mutex);
57     pred = true;
58     cond.signal();
59     }
60     void wait() {
61     Glib::Mutex::Lock lock(mutex);
62     while (!pred) cond.wait(mutex);
63     }
64     };
65    
66     static Glib::StaticMutex mutex;
67     static Glib::Dispatcher* dispatcher;
68     static GigEditState* current;
69    
70     static void main_loop_run(Cond* intialized);
71     static void open_window_static();
72    
73     GigEdit* parent;
74     Cond open;
75     Cond close;
76     gig::Instrument* instrument;
77    
78     void open_window();
79     void close_window();
80     };
81    
82     void init_app() {
83 schoenebeck 1333 static bool process_initialized = false;
84     if (!process_initialized) {
85     std::cout << "Initializing 3rd party services needed by gigedit.\n"
86     << std::flush;
87     setlocale(LC_ALL, "");
88 schoenebeck 1396
89     #if HAVE_GETTEXT
90 schoenebeck 1333 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
91     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
92     textdomain(GETTEXT_PACKAGE);
93 schoenebeck 1396 #endif // HAVE_GETTEXT
94    
95 schoenebeck 1333 // make sure thread_init() is called once and ONLY once per process
96     if (!Glib::thread_supported()) Glib::thread_init();
97    
98     process_initialized = true;
99     }
100 schoenebeck 1225 }
101    
102 persson 1456 void connect_signals(GigEdit* gigedit, MainWindow* mainwindow) {
103 schoenebeck 1322 // the signals of the "GigEdit" class are actually just proxies, that
104     // is they simply forward the signals of the internal classes to the
105     // outer world
106     mainwindow->signal_file_structure_to_be_changed().connect(
107     gigedit->signal_file_structure_to_be_changed().make_slot()
108     );
109     mainwindow->signal_file_structure_changed().connect(
110     gigedit->signal_file_structure_changed().make_slot()
111     );
112     mainwindow->signal_samples_to_be_removed().connect(
113     gigedit->signal_samples_to_be_removed().make_slot()
114     );
115     mainwindow->signal_samples_removed().connect(
116     gigedit->signal_samples_removed().make_slot()
117     );
118     mainwindow->signal_region_to_be_changed().connect(
119     gigedit->signal_region_to_be_changed().make_slot()
120     );
121     mainwindow->signal_region_changed().connect(
122     gigedit->signal_region_changed().make_slot()
123     );
124     mainwindow->signal_dimreg_to_be_changed().connect(
125     gigedit->signal_dimreg_to_be_changed().make_slot()
126     );
127     mainwindow->signal_dimreg_changed().connect(
128     gigedit->signal_dimreg_changed().make_slot()
129     );
130     mainwindow->signal_sample_ref_changed().connect(
131     gigedit->signal_sample_ref_changed().make_slot()
132     );
133     }
134    
135 schoenebeck 1654 } // namespace
136    
137     GigEdit::GigEdit() {
138     state = NULL;
139 schoenebeck 1225 }
140    
141 persson 1456 int GigEdit::run(int argc, char* argv[]) {
142     init_app();
143    
144     Gtk::Main kit(argc, argv);
145 schoenebeck 1225 MainWindow window;
146 persson 1456 connect_signals(this, &window);
147     if (argc >= 2) window.load_file(argv[1]);
148 schoenebeck 1225 kit.run(window);
149     return 0;
150     }
151    
152     int GigEdit::run(gig::Instrument* pInstrument) {
153 persson 1456 init_app();
154    
155     GigEditState state(this);
156 schoenebeck 1654 this->state = &state;
157 persson 1456 state.run(pInstrument);
158 schoenebeck 1654 this->state = NULL;
159 schoenebeck 1225 return 0;
160     }
161 schoenebeck 1322
162 schoenebeck 1654 void GigEdit::on_note_on_event(int key, int velocity) {
163     if (!this->state) return;
164     GigEditState* state = (GigEditState*) this->state;
165     state->window->signal_note_on().emit(key, velocity);
166     }
167    
168     void GigEdit::on_note_off_event(int key, int velocity) {
169     if (!this->state) return;
170     GigEditState* state = (GigEditState*) this->state;
171     state->window->signal_note_off().emit(key, velocity);
172     }
173    
174 schoenebeck 1339 sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_to_be_changed() {
175 schoenebeck 1322 return file_structure_to_be_changed_signal;
176     }
177    
178 schoenebeck 1339 sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_changed() {
179 schoenebeck 1322 return file_structure_changed_signal;
180     }
181    
182 schoenebeck 1339 sigc::signal<void, std::list<gig::Sample*> >& GigEdit::signal_samples_to_be_removed() {
183 schoenebeck 1322 return samples_to_be_removed_signal;
184     }
185    
186 schoenebeck 1339 sigc::signal<void>& GigEdit::signal_samples_removed() {
187 schoenebeck 1322 return samples_removed_signal;
188     }
189    
190 schoenebeck 1339 sigc::signal<void, gig::Region*>& GigEdit::signal_region_to_be_changed() {
191 schoenebeck 1322 return region_to_be_changed_signal;
192     }
193    
194 schoenebeck 1339 sigc::signal<void, gig::Region*>& GigEdit::signal_region_changed() {
195 schoenebeck 1322 return region_changed_signal;
196     }
197    
198 schoenebeck 1339 sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_to_be_changed() {
199 schoenebeck 1322 return dimreg_to_be_changed_signal;
200     }
201    
202 schoenebeck 1339 sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_changed() {
203 schoenebeck 1322 return dimreg_changed_signal;
204     }
205    
206 schoenebeck 1339 sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& GigEdit::signal_sample_ref_changed() {
207 schoenebeck 1322 return sample_ref_changed_signal;
208     }
209 persson 1456
210    
211     Glib::StaticMutex GigEditState::mutex = GLIBMM_STATIC_MUTEX_INIT;
212     Glib::Dispatcher* GigEditState::dispatcher = 0;
213     GigEditState* GigEditState::current = 0;
214    
215     void GigEditState::open_window_static() {
216     GigEditState* c = GigEditState::current;
217     c->open.signal();
218     c->open_window();
219     }
220    
221     void GigEditState::open_window() {
222     window = new MainWindow();
223    
224     connect_signals(parent, window);
225     if (instrument) window->load_instrument(instrument);
226    
227     window->signal_hide().connect(sigc::mem_fun(this,
228     &GigEditState::close_window));
229     window->present();
230     }
231    
232     void GigEditState::close_window() {
233     delete window;
234     close.signal();
235     }
236    
237     void GigEditState::main_loop_run(Cond* initialized) {
238     int argc = 1;
239     const char* argv_c[] = { "gigedit" };
240     char** argv = const_cast<char**>(argv_c);
241     Gtk::Main main_loop(argc, argv);
242    
243     dispatcher = new Glib::Dispatcher();
244     dispatcher->connect(sigc::ptr_fun(&GigEditState::open_window_static));
245     initialized->signal();
246    
247     main_loop.run();
248     }
249    
250     void GigEditState::run(gig::Instrument* pInstrument) {
251     mutex.lock(); // lock access to static variables
252    
253     static bool main_loop_started = false;
254     if (!main_loop_started) {
255     Cond initialized;
256     Glib::Thread::create(
257     sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
258     &initialized),
259     false);
260     initialized.wait();
261     main_loop_started = true;
262     }
263     instrument = pInstrument;
264     current = this;
265     dispatcher->emit();
266     open.wait(); // wait until the GUI thread has read current
267     mutex.unlock();
268     close.wait(); // sleep until window is closed
269     }

  ViewVC Help
Powered by ViewVC