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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1661 - (hide annotations) (download)
Sun Feb 3 14:10:47 2008 UTC (16 years, 1 month ago) by schoenebeck
File size: 64872 byte(s)
* implemented alternative behavior for the virtual MIDI keyboard
  (selectable by combobox below the keyboard)
* show absolute velocity value of note-on & note-off events below
  the virtual MIDI keyboard

1 schoenebeck 1225 /*
2 schoenebeck 1654 * Copyright (C) 2006 - 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 <iostream>
21    
22     #include <gtkmm/filechooserdialog.h>
23     #include <gtkmm/messagedialog.h>
24     #include <gtkmm/stock.h>
25     #include <gtkmm/targetentry.h>
26     #include <gtkmm/main.h>
27 schoenebeck 1415 #include <gtkmm/toggleaction.h>
28 schoenebeck 1225
29 schoenebeck 1396 #include "global.h"
30    
31 persson 1261 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
32 schoenebeck 1225 #define ABOUT_DIALOG
33     #include <gtkmm/aboutdialog.h>
34     #endif
35    
36 persson 1303 #if (GLIBMM_MAJOR_VERSION == 2 && GLIBMM_MINOR_VERSION < 6) || GLIBMM_MAJOR_VERSION < 2
37     namespace Glib {
38     Glib::ustring filename_display_basename(const std::string& filename)
39     {
40     gchar* gstr = g_path_get_basename(filename.c_str());
41     Glib::ustring str(gstr);
42     g_free(gstr);
43     return Glib::filename_to_utf8(str);
44     }
45     }
46     #endif
47    
48 schoenebeck 1225 #include <stdio.h>
49     #include <sndfile.h>
50    
51     #include "mainwindow.h"
52    
53 schoenebeck 1411 #include "../../gfx/status_attached.xpm"
54     #include "../../gfx/status_detached.xpm"
55    
56 schoenebeck 1225 template<class T> inline std::string ToString(T o) {
57     std::stringstream ss;
58     ss << o;
59     return ss.str();
60     }
61    
62 persson 1582 Table::Table(int x, int y) : Gtk::Table(x, y), rowno(0) { }
63    
64     void Table::add(BoolEntry& boolentry)
65     {
66     attach(boolentry.widget, 0, 2, rowno, rowno + 1,
67     Gtk::FILL, Gtk::SHRINK);
68     rowno++;
69     }
70    
71     void Table::add(BoolEntryPlus6& boolentry)
72     {
73     attach(boolentry.widget, 0, 2, rowno, rowno + 1,
74     Gtk::FILL, Gtk::SHRINK);
75     rowno++;
76     }
77    
78     void Table::add(LabelWidget& prop)
79     {
80     attach(prop.label, 1, 2, rowno, rowno + 1,
81     Gtk::FILL, Gtk::SHRINK);
82     attach(prop.widget, 2, 3, rowno, rowno + 1,
83     Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK);
84     rowno++;
85     }
86    
87 persson 1533 MainWindow::MainWindow() :
88     dimreg_label(_("Changes apply to:")),
89     dimreg_all_regions(_("all regions")),
90     dimreg_all_dimregs(_("all dimension splits")),
91     dimreg_stereo(_("both channels"))
92 schoenebeck 1225 {
93     // set_border_width(5);
94     // set_default_size(400, 200);
95    
96    
97     add(m_VBox);
98    
99     // Handle selection
100     Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
101     tree_sel_ref->signal_changed().connect(
102     sigc::mem_fun(*this, &MainWindow::on_sel_change));
103    
104     // m_TreeView.set_reorderable();
105    
106     m_TreeView.signal_button_press_event().connect_notify(
107     sigc::mem_fun(*this, &MainWindow::on_button_release));
108    
109     // Add the TreeView tab, inside a ScrolledWindow, with the button underneath:
110     m_ScrolledWindow.add(m_TreeView);
111     // m_ScrolledWindow.set_size_request(200, 600);
112     m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
113    
114     m_ScrolledWindowSamples.add(m_TreeViewSamples);
115     m_ScrolledWindowSamples.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
116    
117    
118     m_TreeViewNotebook.set_size_request(300);
119    
120     m_HPaned.add1(m_TreeViewNotebook);
121 persson 1533 dimreg_hbox.add(dimreg_label);
122     dimreg_hbox.add(dimreg_all_regions);
123     dimreg_hbox.add(dimreg_all_dimregs);
124     dimreg_stereo.set_active();
125     dimreg_hbox.add(dimreg_stereo);
126     dimreg_vbox.add(dimreg_edit);
127 persson 1582 dimreg_vbox.pack_start(dimreg_hbox, Gtk::PACK_SHRINK);
128 persson 1533 m_HPaned.add2(dimreg_vbox);
129 schoenebeck 1225
130    
131     m_TreeViewNotebook.append_page(m_ScrolledWindowSamples, "Samples");
132     m_TreeViewNotebook.append_page(m_ScrolledWindow, "Instruments");
133    
134    
135     actionGroup = Gtk::ActionGroup::create();
136    
137     actionGroup->add(Gtk::Action::create("MenuFile", _("_File")));
138     actionGroup->add(Gtk::Action::create("New", Gtk::Stock::NEW),
139     sigc::mem_fun(
140     *this, &MainWindow::on_action_file_new));
141     Glib::RefPtr<Gtk::Action> action =
142     Gtk::Action::create("Open", Gtk::Stock::OPEN);
143     action->property_label() = action->property_label() + "...";
144     actionGroup->add(action,
145     sigc::mem_fun(
146     *this, &MainWindow::on_action_file_open));
147     actionGroup->add(Gtk::Action::create("Save", Gtk::Stock::SAVE),
148     sigc::mem_fun(
149     *this, &MainWindow::on_action_file_save));
150     action = Gtk::Action::create("SaveAs", Gtk::Stock::SAVE_AS);
151     action->property_label() = action->property_label() + "...";
152     actionGroup->add(action,
153 persson 1261 Gtk::AccelKey("<shift><control>s"),
154 schoenebeck 1225 sigc::mem_fun(
155 persson 1261 *this, &MainWindow::on_action_file_save_as));
156 schoenebeck 1225 actionGroup->add(Gtk::Action::create("Properties",
157     Gtk::Stock::PROPERTIES),
158     sigc::mem_fun(
159     *this, &MainWindow::on_action_file_properties));
160     actionGroup->add(Gtk::Action::create("InstrProperties",
161     Gtk::Stock::PROPERTIES),
162     sigc::mem_fun(
163     *this, &MainWindow::show_instr_props));
164     actionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT),
165     sigc::mem_fun(
166 persson 1261 *this, &MainWindow::on_action_quit));
167 schoenebeck 1225 actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));
168    
169 schoenebeck 1415 actionGroup->add(Gtk::Action::create("MenuView", _("_View")));
170     Glib::RefPtr<Gtk::ToggleAction> toggle_action =
171     Gtk::ToggleAction::create("Statusbar", _("_Statusbar"));
172     toggle_action->set_active(true);
173     actionGroup->add(toggle_action,
174     sigc::mem_fun(
175     *this, &MainWindow::on_action_view_status_bar));
176    
177 schoenebeck 1225 action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);
178     actionGroup->add(Gtk::Action::create("MenuHelp",
179     action->property_label()));
180     #ifdef ABOUT_DIALOG
181     actionGroup->add(Gtk::Action::create("About", Gtk::Stock::ABOUT),
182     sigc::mem_fun(
183     *this, &MainWindow::on_action_help_about));
184     #endif
185     actionGroup->add(
186     Gtk::Action::create("AddInstrument", _("Add _Instrument")),
187     sigc::mem_fun(*this, &MainWindow::on_action_add_instrument)
188     );
189     actionGroup->add(
190     Gtk::Action::create("RemoveInstrument", Gtk::Stock::REMOVE),
191     sigc::mem_fun(*this, &MainWindow::on_action_remove_instrument)
192     );
193    
194     // sample right-click popup actions
195     actionGroup->add(
196     Gtk::Action::create("SampleProperties", Gtk::Stock::PROPERTIES),
197     sigc::mem_fun(*this, &MainWindow::on_action_sample_properties)
198     );
199     actionGroup->add(
200     Gtk::Action::create("AddGroup", _("Add _Group")),
201     sigc::mem_fun(*this, &MainWindow::on_action_add_group)
202     );
203     actionGroup->add(
204     Gtk::Action::create("AddSample", _("Add _Sample(s)")),
205     sigc::mem_fun(*this, &MainWindow::on_action_add_sample)
206     );
207     actionGroup->add(
208     Gtk::Action::create("RemoveSample", Gtk::Stock::REMOVE),
209     sigc::mem_fun(*this, &MainWindow::on_action_remove_sample)
210     );
211    
212     uiManager = Gtk::UIManager::create();
213     uiManager->insert_action_group(actionGroup);
214 persson 1261 add_accel_group(uiManager->get_accel_group());
215 schoenebeck 1225
216     Glib::ustring ui_info =
217     "<ui>"
218     " <menubar name='MenuBar'>"
219     " <menu action='MenuFile'>"
220     " <menuitem action='New'/>"
221     " <menuitem action='Open'/>"
222     " <separator/>"
223     " <menuitem action='Save'/>"
224     " <menuitem action='SaveAs'/>"
225     " <separator/>"
226     " <menuitem action='Properties'/>"
227     " <separator/>"
228     " <menuitem action='Quit'/>"
229     " </menu>"
230     " <menu action='MenuInstrument'>"
231     " </menu>"
232 schoenebeck 1415 " <menu action='MenuView'>"
233     " <menuitem action='Statusbar'/>"
234     " </menu>"
235 schoenebeck 1225 #ifdef ABOUT_DIALOG
236     " <menu action='MenuHelp'>"
237     " <menuitem action='About'/>"
238     " </menu>"
239     #endif
240     " </menubar>"
241     " <popup name='PopupMenu'>"
242     " <menuitem action='InstrProperties'/>"
243     " <menuitem action='AddInstrument'/>"
244     " <separator/>"
245     " <menuitem action='RemoveInstrument'/>"
246     " </popup>"
247     " <popup name='SamplePopupMenu'>"
248     " <menuitem action='SampleProperties'/>"
249     " <menuitem action='AddGroup'/>"
250     " <menuitem action='AddSample'/>"
251     " <separator/>"
252     " <menuitem action='RemoveSample'/>"
253     " </popup>"
254     "</ui>";
255     uiManager->add_ui_from_string(ui_info);
256    
257     popup_menu = dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/PopupMenu"));
258    
259     Gtk::Widget* menuBar = uiManager->get_widget("/MenuBar");
260     m_VBox.pack_start(*menuBar, Gtk::PACK_SHRINK);
261     m_VBox.pack_start(m_HPaned);
262     m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);
263 schoenebeck 1661 m_VBox.pack_start(m_RegionChooser.m_VirtKeybPropsBox, Gtk::PACK_SHRINK);
264 schoenebeck 1225 m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);
265 schoenebeck 1411 m_VBox.pack_start(m_StatusBar, Gtk::PACK_SHRINK);
266 schoenebeck 1225
267 schoenebeck 1411 // Status Bar:
268     m_StatusBar.pack_start(m_AttachedStateLabel, Gtk::PACK_SHRINK);
269     m_StatusBar.pack_start(m_AttachedStateImage, Gtk::PACK_SHRINK);
270     m_StatusBar.show();
271    
272 persson 1261 m_RegionChooser.signal_region_selected().connect(
273 schoenebeck 1225 sigc::mem_fun(*this, &MainWindow::region_changed) );
274 persson 1261 m_DimRegionChooser.signal_dimregion_selected().connect(
275 schoenebeck 1225 sigc::mem_fun(*this, &MainWindow::dimreg_changed) );
276    
277    
278     // Create the Tree model:
279     m_refTreeModel = Gtk::ListStore::create(m_Columns);
280     m_TreeView.set_model(m_refTreeModel);
281     m_refTreeModel->signal_row_changed().connect(
282     sigc::mem_fun(*this, &MainWindow::instrument_name_changed)
283     );
284    
285     // Add the TreeView's view columns:
286     m_TreeView.append_column_editable("Instrument", m_Columns.m_col_name);
287     m_TreeView.set_headers_visible(false);
288    
289     // create samples treeview (including its data model)
290     m_refSamplesTreeModel = SamplesTreeStore::create(m_SamplesModel);
291     m_TreeViewSamples.set_model(m_refSamplesTreeModel);
292     // m_TreeViewSamples.set_reorderable();
293     m_TreeViewSamples.append_column_editable("Samples", m_SamplesModel.m_col_name);
294     m_TreeViewSamples.set_headers_visible(false);
295     m_TreeViewSamples.signal_button_press_event().connect_notify(
296     sigc::mem_fun(*this, &MainWindow::on_sample_treeview_button_release)
297     );
298     m_refSamplesTreeModel->signal_row_changed().connect(
299     sigc::mem_fun(*this, &MainWindow::sample_name_changed)
300     );
301    
302     // establish drag&drop between samples tree view and dimension region 'Sample' text entry
303     std::list<Gtk::TargetEntry> drag_target_gig_sample;
304     drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );
305     m_TreeViewSamples.drag_source_set(drag_target_gig_sample);
306 persson 1303 m_TreeViewSamples.signal_drag_begin().connect(
307     sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_begin)
308     );
309 schoenebeck 1225 m_TreeViewSamples.signal_drag_data_get().connect(
310     sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)
311     );
312     dimreg_edit.wSample->drag_dest_set(drag_target_gig_sample);
313     dimreg_edit.wSample->signal_drag_data_received().connect(
314     sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)
315     );
316 persson 1261 dimreg_edit.signal_dimreg_changed().connect(
317 schoenebeck 1322 sigc::hide(sigc::mem_fun(*this, &MainWindow::file_changed)));
318 persson 1261 m_RegionChooser.signal_instrument_changed().connect(
319     sigc::mem_fun(*this, &MainWindow::file_changed));
320     m_DimRegionChooser.signal_region_changed().connect(
321     sigc::mem_fun(*this, &MainWindow::file_changed));
322     instrumentProps.signal_instrument_changed().connect(
323     sigc::mem_fun(*this, &MainWindow::file_changed));
324 persson 1582 propDialog.signal_info_changed().connect(
325     sigc::mem_fun(*this, &MainWindow::file_changed));
326 schoenebeck 1322
327     dimreg_edit.signal_dimreg_to_be_changed().connect(
328     dimreg_to_be_changed_signal.make_slot());
329     dimreg_edit.signal_dimreg_changed().connect(
330     dimreg_changed_signal.make_slot());
331     dimreg_edit.signal_sample_ref_changed().connect(
332     sample_ref_changed_signal.make_slot());
333    
334     m_RegionChooser.signal_instrument_struct_to_be_changed().connect(
335     sigc::hide(
336     sigc::bind(
337     file_structure_to_be_changed_signal.make_slot(),
338     sigc::ref(this->file)
339     )
340     )
341     );
342     m_RegionChooser.signal_instrument_struct_changed().connect(
343     sigc::hide(
344     sigc::bind(
345     file_structure_changed_signal.make_slot(),
346     sigc::ref(this->file)
347     )
348     )
349     );
350     m_RegionChooser.signal_region_to_be_changed().connect(
351     region_to_be_changed_signal.make_slot());
352     m_RegionChooser.signal_region_changed_signal().connect(
353     region_changed_signal.make_slot());
354    
355 schoenebeck 1654 note_on_signal.connect(
356     sigc::mem_fun(m_RegionChooser, &RegionChooser::on_note_on_event));
357     note_off_signal.connect(
358     sigc::mem_fun(m_RegionChooser, &RegionChooser::on_note_off_event));
359    
360 persson 1533 dimreg_all_regions.signal_toggled().connect(
361     sigc::mem_fun(*this, &MainWindow::update_dimregs));
362     dimreg_all_dimregs.signal_toggled().connect(
363     sigc::mem_fun(*this, &MainWindow::dimreg_all_dimregs_toggled));
364     dimreg_stereo.signal_toggled().connect(
365     sigc::mem_fun(*this, &MainWindow::update_dimregs));
366    
367 schoenebeck 1225 file = 0;
368 persson 1261 file_is_changed = false;
369 schoenebeck 1411 set_file_is_shared(false);
370 schoenebeck 1225
371     show_all_children();
372 schoenebeck 1300
373     // start with a new gig file by default
374     on_action_file_new();
375 schoenebeck 1225 }
376    
377     MainWindow::~MainWindow()
378     {
379     }
380    
381 persson 1261 bool MainWindow::on_delete_event(GdkEventAny* event)
382     {
383 schoenebeck 1382 return !file_is_shared && file_is_changed && !close_confirmation_dialog();
384 persson 1261 }
385    
386     void MainWindow::on_action_quit()
387     {
388 schoenebeck 1382 if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
389 persson 1261 hide();
390     }
391    
392 schoenebeck 1225 void MainWindow::region_changed()
393     {
394     m_DimRegionChooser.set_region(m_RegionChooser.get_region());
395     }
396    
397 persson 1533 gig::Instrument* MainWindow::get_instrument()
398 schoenebeck 1225 {
399 persson 1533 gig::Instrument* instrument = 0;
400 schoenebeck 1225 Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
401    
402     Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
403     if (it) {
404     Gtk::TreeModel::Row row = *it;
405 persson 1533 instrument = row[m_Columns.m_col_instr];
406     }
407     return instrument;
408     }
409 schoenebeck 1225
410 persson 1533 void MainWindow::add_region_to_dimregs(gig::Region* region, bool stereo, bool all_dimregs)
411     {
412     if (all_dimregs) {
413     for (int i = 0 ; i < region->DimensionRegions ; i++) {
414     if (region->pDimensionRegions[i]) {
415     dimreg_edit.dimregs.insert(region->pDimensionRegions[i]);
416     }
417     }
418 schoenebeck 1225 } else {
419 persson 1533 m_DimRegionChooser.get_dimregions(region, stereo, dimreg_edit.dimregs);
420 schoenebeck 1225 }
421     }
422    
423 persson 1533 void MainWindow::update_dimregs()
424     {
425     dimreg_edit.dimregs.clear();
426     bool all_regions = dimreg_all_regions.get_active();
427     bool stereo = dimreg_stereo.get_active();
428     bool all_dimregs = dimreg_all_dimregs.get_active();
429    
430     if (all_regions) {
431     gig::Instrument* instrument = get_instrument();
432     if (instrument) {
433     for (gig::Region* region = instrument->GetFirstRegion() ;
434     region ;
435     region = instrument->GetNextRegion()) {
436     add_region_to_dimregs(region, stereo, all_dimregs);
437     }
438     }
439     } else {
440     gig::Region* region = m_RegionChooser.get_region();
441     if (region) {
442     add_region_to_dimregs(region, stereo, all_dimregs);
443     }
444     }
445     }
446    
447     void MainWindow::dimreg_all_dimregs_toggled()
448     {
449     dimreg_stereo.set_sensitive(!dimreg_all_dimregs.get_active());
450     update_dimregs();
451     }
452    
453     void MainWindow::dimreg_changed()
454     {
455     update_dimregs();
456     dimreg_edit.set_dim_region(m_DimRegionChooser.get_dimregion());
457     }
458    
459     void MainWindow::on_sel_change()
460     {
461     m_RegionChooser.set_instrument(get_instrument());
462     }
463    
464 schoenebeck 1225 void loader_progress_callback(gig::progress_t* progress)
465     {
466     Loader* loader = static_cast<Loader*>(progress->custom);
467     loader->progress_callback(progress->factor);
468     }
469    
470     void Loader::progress_callback(float fraction)
471     {
472     {
473     Glib::Mutex::Lock lock(progressMutex);
474     progress = fraction;
475     }
476     progress_dispatcher();
477     }
478    
479     void Loader::thread_function()
480     {
481     printf("thread_function self=%x\n", Glib::Thread::self());
482     printf("Start %s\n", filename);
483     RIFF::File* riff = new RIFF::File(filename);
484     gig = new gig::File(riff);
485     gig::progress_t progress;
486     progress.callback = loader_progress_callback;
487     progress.custom = this;
488    
489     gig->GetInstrument(0, &progress);
490     printf("End\n");
491     finished_dispatcher();
492     }
493    
494     Loader::Loader(const char* filename)
495     : thread(0), filename(filename)
496     {
497     }
498    
499     void Loader::launch()
500     {
501     thread = Glib::Thread::create(sigc::mem_fun(*this, &Loader::thread_function), true);
502     printf("launch thread=%x\n", thread);
503     }
504    
505     float Loader::get_progress()
506     {
507     float res;
508     {
509     Glib::Mutex::Lock lock(progressMutex);
510     res = progress;
511     }
512     return res;
513     }
514    
515     Glib::Dispatcher& Loader::signal_progress()
516     {
517     return progress_dispatcher;
518     }
519    
520     Glib::Dispatcher& Loader::signal_finished()
521     {
522     return finished_dispatcher;
523     }
524    
525     LoadDialog::LoadDialog(const Glib::ustring& title, Gtk::Window& parent)
526     : Gtk::Dialog(title, parent, true)
527     {
528     get_vbox()->pack_start(progressBar);
529     show_all_children();
530     }
531    
532     // Clear all GUI elements / controls. This method is typically called
533     // before a new .gig file is to be created or to be loaded.
534     void MainWindow::__clear() {
535     // remove all entries from "Instrument" menu
536     Gtk::MenuItem* instrument_menu =
537     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));
538     instrument_menu->hide();
539     for (int i = 0; i < instrument_menu->get_submenu()->items().size(); i++) {
540     delete &instrument_menu->get_submenu()->items()[i];
541     }
542     instrument_menu->get_submenu()->items().clear();
543     // forget all samples that ought to be imported
544     m_SampleImportQueue.clear();
545     // clear the samples and instruments tree views
546     m_refTreeModel->clear();
547     m_refSamplesTreeModel->clear();
548     // free libgig's gig::File instance
549 schoenebeck 1382 if (file && !file_is_shared) delete file;
550     file = NULL;
551 schoenebeck 1411 set_file_is_shared(false);
552 schoenebeck 1225 }
553    
554     void MainWindow::on_action_file_new()
555     {
556 schoenebeck 1382 if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
557 persson 1261
558 schoenebeck 1382 if (file_is_shared && !leaving_shared_mode_dialog()) return;
559    
560 schoenebeck 1225 // clear all GUI elements
561     __clear();
562     // create a new .gig file (virtually yet)
563     gig::File* pFile = new gig::File;
564     // already add one new instrument by default
565     gig::Instrument* pInstrument = pFile->AddInstrument();
566     pInstrument->pInfo->Name = "Unnamed Instrument";
567     // update GUI with that new gig::File
568 persson 1261 load_gig(pFile, 0 /*no file name yet*/);
569 schoenebeck 1225 }
570    
571 persson 1261 bool MainWindow::close_confirmation_dialog()
572     {
573     gchar* msg = g_strdup_printf(_("Save changes to \"%s\" before closing?"),
574     Glib::filename_display_basename(filename).c_str());
575     Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
576     g_free(msg);
577 persson 1303 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
578 persson 1261 dialog.set_secondary_text(_("If you close without saving, your changes will be lost."));
579 persson 1303 #endif
580 persson 1261 dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);
581     dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
582     dialog.add_button(file_has_name ? Gtk::Stock::SAVE : Gtk::Stock::SAVE_AS, Gtk::RESPONSE_YES);
583     dialog.set_default_response(Gtk::RESPONSE_YES);
584     int response = dialog.run();
585 persson 1303 dialog.hide();
586 persson 1261 if (response == Gtk::RESPONSE_YES) return file_save();
587     return response != Gtk::RESPONSE_CANCEL;
588     }
589    
590 schoenebeck 1382 bool MainWindow::leaving_shared_mode_dialog() {
591     Glib::ustring msg = _("Detach from sampler and proceed working stand-alone?");
592     Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
593     #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
594     dialog.set_secondary_text(
595     _("If you proceed to work on another instrument file, it won't be "
596     "used by the sampler until you tell the sampler explicitly to "
597     "load it.")
598     );
599     #endif
600     dialog.add_button(_("_Yes, Detach"), Gtk::RESPONSE_YES);
601     dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
602     dialog.set_default_response(Gtk::RESPONSE_CANCEL);
603     int response = dialog.run();
604     dialog.hide();
605     return response == Gtk::RESPONSE_YES;
606     }
607    
608 schoenebeck 1225 void MainWindow::on_action_file_open()
609     {
610 schoenebeck 1382 if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
611 persson 1261
612 schoenebeck 1382 if (file_is_shared && !leaving_shared_mode_dialog()) return;
613    
614 schoenebeck 1225 Gtk::FileChooserDialog dialog(*this, _("Open file"));
615     dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
616     dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
617 persson 1261 dialog.set_default_response(Gtk::RESPONSE_OK);
618 schoenebeck 1225 Gtk::FileFilter filter;
619     filter.add_pattern("*.gig");
620     dialog.set_filter(filter);
621 persson 1261 if (current_dir != "") {
622     dialog.set_current_folder(current_dir);
623     }
624 schoenebeck 1225 if (dialog.run() == Gtk::RESPONSE_OK) {
625 persson 1261 std::string filename = dialog.get_filename();
626     printf("filename=%s\n", filename.c_str());
627 schoenebeck 1225 printf("on_action_file_open self=%x\n", Glib::Thread::self());
628 persson 1261 load_file(filename.c_str());
629     current_dir = Glib::path_get_dirname(filename);
630 schoenebeck 1225 }
631     }
632    
633     void MainWindow::load_file(const char* name)
634     {
635 persson 1303 __clear();
636 schoenebeck 1225 load_dialog = new LoadDialog("Loading...", *this);
637     load_dialog->show_all();
638     loader = new Loader(strdup(name));
639     loader->signal_progress().connect(
640     sigc::mem_fun(*this, &MainWindow::on_loader_progress));
641     loader->signal_finished().connect(
642     sigc::mem_fun(*this, &MainWindow::on_loader_finished));
643     loader->launch();
644     }
645    
646     void MainWindow::load_instrument(gig::Instrument* instr) {
647     if (!instr) {
648     Glib::ustring txt = "Provided instrument is NULL!\n";
649     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
650     msg.run();
651     Gtk::Main::quit();
652     }
653 schoenebeck 1328 // clear all GUI elements
654     __clear();
655     // load the instrument
656 schoenebeck 1225 gig::File* pFile = (gig::File*) instr->GetParent();
657 schoenebeck 1382 load_gig(pFile, 0 /*file name*/, true /*shared instrument*/);
658 schoenebeck 1225 //TODO: automatically select the given instrument
659     }
660    
661     void MainWindow::on_loader_progress()
662     {
663     load_dialog->set_fraction(loader->get_progress());
664     }
665    
666     void MainWindow::on_loader_finished()
667     {
668     printf("Loader finished!\n");
669     printf("on_loader_finished self=%x\n", Glib::Thread::self());
670     load_gig(loader->gig, loader->filename);
671     load_dialog->hide();
672     }
673    
674     void MainWindow::on_action_file_save()
675     {
676 persson 1261 file_save();
677     }
678    
679 persson 1303 bool MainWindow::check_if_savable()
680     {
681     if (!file) return false;
682    
683     if (!file->GetFirstSample()) {
684     Gtk::MessageDialog(*this, _("The file could not be saved "
685     "because it contains no samples"),
686     false, Gtk::MESSAGE_ERROR).run();
687     return false;
688     }
689    
690     for (gig::Instrument* instrument = file->GetFirstInstrument() ; instrument ;
691     instrument = file->GetNextInstrument()) {
692     if (!instrument->GetFirstRegion()) {
693     Gtk::MessageDialog(*this, _("The file could not be saved "
694     "because there are instruments "
695     "that have no regions"),
696     false, Gtk::MESSAGE_ERROR).run();
697     return false;
698     }
699     }
700     return true;
701     }
702    
703 persson 1261 bool MainWindow::file_save()
704     {
705 persson 1303 if (!check_if_savable()) return false;
706 schoenebeck 1382 if (!file_is_shared && !file_has_name) return file_save_as();
707 persson 1261
708 schoenebeck 1225 std::cout << "Saving file\n" << std::flush;
709 schoenebeck 1322 file_structure_to_be_changed_signal.emit(this->file);
710 schoenebeck 1225 try {
711     file->Save();
712 persson 1261 if (file_is_changed) {
713     set_title(get_title().substr(1));
714     file_is_changed = false;
715     }
716 schoenebeck 1225 } catch (RIFF::Exception e) {
717 schoenebeck 1322 file_structure_changed_signal.emit(this->file);
718 schoenebeck 1382 Glib::ustring txt = _("Could not save file: ") + e.Message;
719 schoenebeck 1225 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
720     msg.run();
721 persson 1261 return false;
722 schoenebeck 1225 }
723     std::cout << "Saving file done\n" << std::flush;
724     __import_queued_samples();
725 schoenebeck 1322 file_structure_changed_signal.emit(this->file);
726 persson 1261 return true;
727 schoenebeck 1225 }
728    
729     void MainWindow::on_action_file_save_as()
730     {
731 persson 1303 if (!check_if_savable()) return;
732 persson 1261 file_save_as();
733     }
734    
735     bool MainWindow::file_save_as()
736     {
737     Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE);
738 schoenebeck 1225 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
739     dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
740 persson 1261 dialog.set_default_response(Gtk::RESPONSE_OK);
741    
742     #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 8) || GTKMM_MAJOR_VERSION > 2
743     dialog.set_do_overwrite_confirmation();
744     // TODO: an overwrite dialog for gtkmm < 2.8
745     #endif
746 schoenebeck 1225 Gtk::FileFilter filter;
747     filter.add_pattern("*.gig");
748     dialog.set_filter(filter);
749 persson 1261
750     if (Glib::path_is_absolute(filename)) {
751     dialog.set_filename(filename);
752     } else if (current_dir != "") {
753     dialog.set_current_folder(current_dir);
754     }
755     dialog.set_current_name(Glib::filename_display_basename(filename));
756    
757 schoenebeck 1225 if (dialog.run() == Gtk::RESPONSE_OK) {
758 schoenebeck 1322 file_structure_to_be_changed_signal.emit(this->file);
759 schoenebeck 1225 try {
760 persson 1261 std::string filename = dialog.get_filename();
761     if (!Glib::str_has_suffix(filename, ".gig")) {
762     filename += ".gig";
763     }
764     printf("filename=%s\n", filename.c_str());
765     file->Save(filename);
766     this->filename = filename;
767     current_dir = Glib::path_get_dirname(filename);
768     set_title(Glib::filename_display_basename(filename));
769     file_has_name = true;
770     file_is_changed = false;
771 schoenebeck 1225 } catch (RIFF::Exception e) {
772 schoenebeck 1322 file_structure_changed_signal.emit(this->file);
773 schoenebeck 1382 Glib::ustring txt = _("Could not save file: ") + e.Message;
774 schoenebeck 1225 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
775     msg.run();
776 persson 1261 return false;
777 schoenebeck 1225 }
778     __import_queued_samples();
779 schoenebeck 1322 file_structure_changed_signal.emit(this->file);
780 persson 1261 return true;
781 schoenebeck 1225 }
782 persson 1261 return false;
783 schoenebeck 1225 }
784    
785     // actually write the sample(s)' data to the gig file
786     void MainWindow::__import_queued_samples() {
787     std::cout << "Starting sample import\n" << std::flush;
788     Glib::ustring error_files;
789     printf("Samples to import: %d\n", m_SampleImportQueue.size());
790     for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
791     iter != m_SampleImportQueue.end(); ) {
792     printf("Importing sample %s\n",(*iter).sample_path.c_str());
793     SF_INFO info;
794     info.format = 0;
795     SNDFILE* hFile = sf_open((*iter).sample_path.c_str(), SFM_READ, &info);
796     try {
797     if (!hFile) throw std::string("could not open file");
798     // determine sample's bit depth
799     int bitdepth;
800     switch (info.format & 0xff) {
801     case SF_FORMAT_PCM_S8:
802     case SF_FORMAT_PCM_16:
803 persson 1265 case SF_FORMAT_PCM_U8:
804 schoenebeck 1225 bitdepth = 16;
805     break;
806     case SF_FORMAT_PCM_24:
807     case SF_FORMAT_PCM_32:
808     case SF_FORMAT_FLOAT:
809     case SF_FORMAT_DOUBLE:
810 persson 1265 bitdepth = 24;
811 schoenebeck 1225 break;
812     default:
813     sf_close(hFile); // close sound file
814     throw std::string("format not supported"); // unsupported subformat (yet?)
815     }
816 persson 1265
817     const int bufsize = 10000;
818 schoenebeck 1225 switch (bitdepth) {
819 persson 1265 case 16: {
820     short* buffer = new short[bufsize * info.channels];
821     sf_count_t cnt = info.frames;
822     while (cnt) {
823     // libsndfile does the conversion for us (if needed)
824     int n = sf_readf_short(hFile, buffer, bufsize);
825     // write from buffer directly (physically) into .gig file
826     iter->gig_sample->Write(buffer, n);
827     cnt -= n;
828     }
829     delete[] buffer;
830 schoenebeck 1225 break;
831 persson 1265 }
832     case 24: {
833     int* srcbuf = new int[bufsize * info.channels];
834     uint8_t* dstbuf = new uint8_t[bufsize * 3 * info.channels];
835     sf_count_t cnt = info.frames;
836     while (cnt) {
837     // libsndfile returns 32 bits, convert to 24
838     int n = sf_readf_int(hFile, srcbuf, bufsize);
839     int j = 0;
840     for (int i = 0 ; i < n * info.channels ; i++) {
841     dstbuf[j++] = srcbuf[i] >> 8;
842     dstbuf[j++] = srcbuf[i] >> 16;
843     dstbuf[j++] = srcbuf[i] >> 24;
844     }
845     // write from buffer directly (physically) into .gig file
846     iter->gig_sample->Write(dstbuf, n);
847     cnt -= n;
848     }
849     delete[] srcbuf;
850     delete[] dstbuf;
851 schoenebeck 1225 break;
852 persson 1265 }
853 schoenebeck 1225 }
854     // cleanup
855     sf_close(hFile);
856     // on success we remove the sample from the import queue,
857     // otherwise keep it, maybe it works the next time ?
858     std::list<SampleImportItem>::iterator cur = iter;
859     ++iter;
860     m_SampleImportQueue.erase(cur);
861     } catch (std::string what) {
862     // remember the files that made trouble (and their cause)
863     if (error_files.size()) error_files += "\n";
864     error_files += (*iter).sample_path += " (" + what + ")";
865     ++iter;
866     }
867     }
868     // show error message box when some sample(s) could not be imported
869     if (error_files.size()) {
870 schoenebeck 1382 Glib::ustring txt = _("Could not import the following sample(s):\n") + error_files;
871 schoenebeck 1225 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
872     msg.run();
873     }
874     }
875    
876     void MainWindow::on_action_file_properties()
877     {
878     propDialog.show();
879     propDialog.deiconify();
880     }
881    
882     void MainWindow::on_action_help_about()
883     {
884     #ifdef ABOUT_DIALOG
885     Gtk::AboutDialog dialog;
886     dialog.set_version(VERSION);
887 schoenebeck 1436 dialog.set_copyright("Copyright (C) 2006,2007 Andreas Persson");
888     dialog.set_comments(
889     "Released under the GNU General Public License.\n"
890     "\n"
891     "Please notice that this is still a very young instrument editor. "
892     "So better backup your Gigasampler files before editing them with "
893     "this application.\n"
894     "\n"
895     "Please report bugs to: http://bugs.linuxsampler.org"
896     );
897     dialog.set_website("http://www.linuxsampler.org");
898     dialog.set_website_label("http://www.linuxsampler.org");
899 schoenebeck 1225 dialog.run();
900     #endif
901     }
902    
903     PropDialog::PropDialog()
904 persson 1582 : table(2,1),
905     eName("Name"),
906     eCreationDate("Creation date"),
907     eComments("Comments"),
908     eProduct("Product"),
909     eCopyright("Copyright"),
910     eArtists("Artists"),
911     eGenre("Genre"),
912     eKeywords("Keywords"),
913     eEngineer("Engineer"),
914     eTechnician("Technician"),
915     eSoftware("Software"),
916     eMedium("Medium"),
917     eSource("Source"),
918     eSourceForm("Source form"),
919     eCommissioned("Commissioned"),
920     eSubject("Subject"),
921     quitButton(Gtk::Stock::CLOSE),
922     update_model(0)
923 schoenebeck 1225 {
924 persson 1582 set_title("File Properties");
925     eName.set_width_chars(50);
926    
927     connect(eName, &DLS::Info::Name);
928     connect(eCreationDate, &DLS::Info::CreationDate);
929     connect(eComments, &DLS::Info::Comments);
930     connect(eProduct, &DLS::Info::Product);
931     connect(eCopyright, &DLS::Info::Copyright);
932     connect(eArtists, &DLS::Info::Artists);
933     connect(eGenre, &DLS::Info::Genre);
934     connect(eKeywords, &DLS::Info::Keywords);
935     connect(eEngineer, &DLS::Info::Engineer);
936     connect(eTechnician, &DLS::Info::Technician);
937     connect(eSoftware, &DLS::Info::Software);
938     connect(eMedium, &DLS::Info::Medium);
939     connect(eSource, &DLS::Info::Source);
940     connect(eSourceForm, &DLS::Info::SourceForm);
941     connect(eCommissioned, &DLS::Info::Commissioned);
942     connect(eSubject, &DLS::Info::Subject);
943    
944     table.add(eName);
945     table.add(eCreationDate);
946     table.add(eComments);
947     table.add(eProduct);
948     table.add(eCopyright);
949     table.add(eArtists);
950     table.add(eGenre);
951     table.add(eKeywords);
952     table.add(eEngineer);
953     table.add(eTechnician);
954     table.add(eSoftware);
955     table.add(eMedium);
956     table.add(eSource);
957     table.add(eSourceForm);
958     table.add(eCommissioned);
959     table.add(eSubject);
960    
961 schoenebeck 1225 table.set_col_spacings(5);
962 persson 1582 add(vbox);
963     table.set_border_width(5);
964     vbox.add(table);
965     vbox.pack_start(buttonBox, Gtk::PACK_SHRINK);
966     buttonBox.set_layout(Gtk::BUTTONBOX_END);
967     buttonBox.set_border_width(5);
968     buttonBox.show();
969     buttonBox.pack_start(quitButton);
970     quitButton.set_flags(Gtk::CAN_DEFAULT);
971     quitButton.grab_focus();
972     quitButton.signal_clicked().connect(
973     sigc::mem_fun(*this, &PropDialog::hide));
974 schoenebeck 1225
975 persson 1582 quitButton.show();
976     vbox.show();
977 schoenebeck 1225 show_all_children();
978     }
979    
980     void PropDialog::set_info(DLS::Info* info)
981     {
982 persson 1582 this->info = info;
983     update_model++;
984     eName.set_value(info->Name);
985     eCreationDate.set_value(info->CreationDate);
986     eComments.set_value(info->Comments);
987     eProduct.set_value(info->Product);
988     eCopyright.set_value(info->Copyright);
989     eArtists.set_value(info->Artists);
990     eGenre.set_value(info->Genre);
991     eKeywords.set_value(info->Keywords);
992     eEngineer.set_value(info->Engineer);
993     eTechnician.set_value(info->Technician);
994     eSoftware.set_value(info->Software);
995     eMedium.set_value(info->Medium);
996     eSource.set_value(info->Source);
997     eSourceForm.set_value(info->SourceForm);
998     eCommissioned.set_value(info->Commissioned);
999     eSubject.set_value(info->Subject);
1000     update_model--;
1001 schoenebeck 1225 }
1002    
1003 persson 1582 sigc::signal<void>& PropDialog::signal_info_changed()
1004     {
1005     return info_changed;
1006     }
1007    
1008 persson 1460 void InstrumentProps::set_IsDrum(bool value)
1009     {
1010     instrument->IsDrum = value;
1011     }
1012    
1013     void InstrumentProps::set_MIDIBank(uint16_t value)
1014     {
1015     instrument->MIDIBank = value;
1016     }
1017    
1018     void InstrumentProps::set_MIDIProgram(uint32_t value)
1019     {
1020     instrument->MIDIProgram = value;
1021     }
1022    
1023     void InstrumentProps::set_DimensionKeyRange_low(uint8_t value)
1024     {
1025     instrument->DimensionKeyRange.low = value;
1026     if (value > instrument->DimensionKeyRange.high) {
1027     eDimensionKeyRangeHigh.set_value(value);
1028     }
1029     }
1030    
1031     void InstrumentProps::set_DimensionKeyRange_high(uint8_t value)
1032     {
1033     instrument->DimensionKeyRange.high = value;
1034     if (value < instrument->DimensionKeyRange.low) {
1035     eDimensionKeyRangeLow.set_value(value);
1036     }
1037     }
1038    
1039 schoenebeck 1225 InstrumentProps::InstrumentProps()
1040     : table(2,1),
1041     quitButton(Gtk::Stock::CLOSE),
1042     eName("Name"),
1043 persson 1262 eIsDrum("Is drum"),
1044     eMIDIBank("MIDI bank", 0, 16383),
1045     eMIDIProgram("MIDI program"),
1046 schoenebeck 1225 eAttenuation("Attenuation", 0, 96, 0, 1),
1047     eGainPlus6("Gain +6dB", eAttenuation, -6),
1048 persson 1262 eEffectSend("Effect send", 0, 65535),
1049     eFineTune("Fine tune", -8400, 8400),
1050     ePitchbendRange("Pitchbend range", 0, 12),
1051     ePianoReleaseMode("Piano release mode"),
1052 schoenebeck 1656 eDimensionKeyRangeLow("Keyswitching range low"),
1053     eDimensionKeyRangeHigh("Keyswitching range high"),
1054 persson 1460 update_model(0)
1055 schoenebeck 1225 {
1056 persson 1582 set_title("Instrument Properties");
1057 schoenebeck 1225
1058 schoenebeck 1656 eDimensionKeyRangeLow.set_tip(
1059     _("start of the keyboard area which should switch the "
1060     "\"keyswitching\" dimension")
1061     );
1062     eDimensionKeyRangeHigh.set_tip(
1063     _("end of the keyboard area which should switch the "
1064     "\"keyswitching\" dimension")
1065     );
1066    
1067 persson 1460 connect(eIsDrum, &InstrumentProps::set_IsDrum);
1068     connect(eMIDIBank, &InstrumentProps::set_MIDIBank);
1069     connect(eMIDIProgram, &InstrumentProps::set_MIDIProgram);
1070     connect(eAttenuation, &gig::Instrument::Attenuation);
1071     connect(eGainPlus6, &gig::Instrument::Attenuation);
1072     connect(eEffectSend, &gig::Instrument::EffectSend);
1073     connect(eFineTune, &gig::Instrument::FineTune);
1074     connect(ePitchbendRange, &gig::Instrument::PitchbendRange);
1075     connect(ePianoReleaseMode, &gig::Instrument::PianoReleaseMode);
1076     connect(eDimensionKeyRangeLow,
1077     &InstrumentProps::set_DimensionKeyRange_low);
1078     connect(eDimensionKeyRangeHigh,
1079     &InstrumentProps::set_DimensionKeyRange_high);
1080    
1081 schoenebeck 1225 table.set_col_spacings(5);
1082    
1083 persson 1582 table.add(eName);
1084     table.add(eIsDrum);
1085     table.add(eMIDIBank);
1086     table.add(eMIDIProgram);
1087     table.add(eAttenuation);
1088     table.add(eGainPlus6);
1089     table.add(eEffectSend);
1090     table.add(eFineTune);
1091     table.add(ePitchbendRange);
1092     table.add(ePianoReleaseMode);
1093     table.add(eDimensionKeyRangeLow);
1094     table.add(eDimensionKeyRangeHigh);
1095 schoenebeck 1225
1096     add(vbox);
1097     table.set_border_width(5);
1098     vbox.pack_start(table);
1099     table.show();
1100     vbox.pack_start(buttonBox, Gtk::PACK_SHRINK);
1101     buttonBox.set_layout(Gtk::BUTTONBOX_END);
1102     buttonBox.set_border_width(5);
1103     buttonBox.show();
1104     buttonBox.pack_start(quitButton);
1105     quitButton.set_flags(Gtk::CAN_DEFAULT);
1106     quitButton.grab_focus();
1107    
1108     quitButton.signal_clicked().connect(
1109     sigc::mem_fun(*this, &InstrumentProps::hide));
1110    
1111     quitButton.show();
1112     vbox.show();
1113     show_all_children();
1114     }
1115    
1116     void InstrumentProps::set_instrument(gig::Instrument* instrument)
1117     {
1118 persson 1460 this->instrument = instrument;
1119    
1120     update_model++;
1121 persson 1582 eName.set_value(instrument->pInfo->Name);
1122 persson 1460 eIsDrum.set_value(instrument->IsDrum);
1123     eMIDIBank.set_value(instrument->MIDIBank);
1124     eMIDIProgram.set_value(instrument->MIDIProgram);
1125     eAttenuation.set_value(instrument->Attenuation);
1126     eGainPlus6.set_value(instrument->Attenuation);
1127     eEffectSend.set_value(instrument->EffectSend);
1128     eFineTune.set_value(instrument->FineTune);
1129     ePitchbendRange.set_value(instrument->PitchbendRange);
1130     ePianoReleaseMode.set_value(instrument->PianoReleaseMode);
1131     eDimensionKeyRangeLow.set_value(instrument->DimensionKeyRange.low);
1132     eDimensionKeyRangeHigh.set_value(instrument->DimensionKeyRange.high);
1133     update_model--;
1134 schoenebeck 1225 }
1135    
1136 schoenebeck 1339 sigc::signal<void>& InstrumentProps::signal_instrument_changed()
1137 schoenebeck 1225 {
1138 persson 1261 return instrument_changed;
1139     }
1140 schoenebeck 1225
1141 persson 1261 void MainWindow::file_changed()
1142     {
1143     if (file && !file_is_changed) {
1144     set_title("*" + get_title());
1145     file_is_changed = true;
1146 schoenebeck 1225 }
1147 persson 1261 }
1148 schoenebeck 1225
1149 schoenebeck 1382 void MainWindow::load_gig(gig::File* gig, const char* filename, bool isSharedInstrument)
1150 persson 1261 {
1151     file = 0;
1152 schoenebeck 1411 set_file_is_shared(isSharedInstrument);
1153 persson 1261
1154     this->filename = filename ? filename : _("Unsaved Gig File");
1155     set_title(Glib::filename_display_basename(this->filename));
1156     file_has_name = filename;
1157     file_is_changed = false;
1158    
1159 schoenebeck 1225 propDialog.set_info(gig->pInfo);
1160    
1161     Gtk::MenuItem* instrument_menu =
1162     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));
1163    
1164     int instrument_index = 0;
1165     Gtk::RadioMenuItem::Group instrument_group;
1166     for (gig::Instrument* instrument = gig->GetFirstInstrument() ; instrument ;
1167     instrument = gig->GetNextInstrument()) {
1168     Gtk::TreeModel::iterator iter = m_refTreeModel->append();
1169     Gtk::TreeModel::Row row = *iter;
1170     row[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
1171     row[m_Columns.m_col_instr] = instrument;
1172     // create a menu item for this instrument
1173     Gtk::RadioMenuItem* item =
1174     new Gtk::RadioMenuItem(instrument_group, instrument->pInfo->Name.c_str());
1175     instrument_menu->get_submenu()->append(*item);
1176     item->signal_activate().connect(
1177     sigc::bind(
1178     sigc::mem_fun(*this, &MainWindow::on_instrument_selection_change),
1179     instrument_index
1180     )
1181     );
1182     instrument_index++;
1183     }
1184     instrument_menu->show();
1185     instrument_menu->get_submenu()->show_all_children();
1186    
1187     for (gig::Group* group = gig->GetFirstGroup(); group; group = gig->GetNextGroup()) {
1188     if (group->Name != "") {
1189     Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
1190     Gtk::TreeModel::Row rowGroup = *iterGroup;
1191     rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1192     rowGroup[m_SamplesModel.m_col_group] = group;
1193     rowGroup[m_SamplesModel.m_col_sample] = NULL;
1194     for (gig::Sample* sample = group->GetFirstSample();
1195     sample; sample = group->GetNextSample()) {
1196     Gtk::TreeModel::iterator iterSample =
1197     m_refSamplesTreeModel->append(rowGroup.children());
1198     Gtk::TreeModel::Row rowSample = *iterSample;
1199     rowSample[m_SamplesModel.m_col_name] = sample->pInfo->Name.c_str();
1200     rowSample[m_SamplesModel.m_col_sample] = sample;
1201     rowSample[m_SamplesModel.m_col_group] = NULL;
1202     }
1203     }
1204     }
1205    
1206 persson 1261 file = gig;
1207    
1208 schoenebeck 1225 // select the first instrument
1209     Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
1210     tree_sel_ref->select(Gtk::TreePath("0"));
1211     }
1212    
1213     void MainWindow::show_instr_props()
1214     {
1215 persson 1533 gig::Instrument* instrument = get_instrument();
1216     if (instrument)
1217 schoenebeck 1225 {
1218 persson 1533 instrumentProps.set_instrument(instrument);
1219     instrumentProps.show();
1220     instrumentProps.deiconify();
1221 schoenebeck 1225 }
1222     }
1223    
1224 schoenebeck 1415 void MainWindow::on_action_view_status_bar() {
1225     Gtk::CheckMenuItem* item =
1226     dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuView/Statusbar"));
1227     if (!item) {
1228     std::cerr << "/MenuBar/MenuView/Statusbar == NULL\n";
1229     return;
1230     }
1231     if (item->get_active()) m_StatusBar.show();
1232     else m_StatusBar.hide();
1233     }
1234    
1235 schoenebeck 1225 void MainWindow::on_button_release(GdkEventButton* button)
1236     {
1237     if (button->type == GDK_2BUTTON_PRESS) {
1238     show_instr_props();
1239     } else if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
1240     popup_menu->popup(button->button, button->time);
1241     }
1242     }
1243    
1244     void MainWindow::on_instrument_selection_change(int index) {
1245     m_RegionChooser.set_instrument(file->GetInstrument(index));
1246     }
1247    
1248     void MainWindow::on_sample_treeview_button_release(GdkEventButton* button) {
1249     if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
1250     Gtk::Menu* sample_popup =
1251     dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/SamplePopupMenu"));
1252     // update enabled/disabled state of sample popup items
1253     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1254     Gtk::TreeModel::iterator it = sel->get_selected();
1255     bool group_selected = false;
1256     bool sample_selected = false;
1257     if (it) {
1258     Gtk::TreeModel::Row row = *it;
1259     group_selected = row[m_SamplesModel.m_col_group];
1260     sample_selected = row[m_SamplesModel.m_col_sample];
1261     }
1262     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/SampleProperties"))->
1263     set_sensitive(group_selected || sample_selected);
1264     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddSample"))->
1265     set_sensitive(group_selected || sample_selected);
1266     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddGroup"))->
1267     set_sensitive(file);
1268     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/RemoveSample"))->
1269     set_sensitive(group_selected || sample_selected);
1270     // show sample popup
1271     sample_popup->popup(button->button, button->time);
1272     }
1273     }
1274    
1275     void MainWindow::on_action_add_instrument() {
1276     static int __instrument_indexer = 0;
1277     if (!file) return;
1278     gig::Instrument* instrument = file->AddInstrument();
1279     __instrument_indexer++;
1280     instrument->pInfo->Name =
1281     "Unnamed Instrument " + ToString(__instrument_indexer);
1282     // update instrument tree view
1283     Gtk::TreeModel::iterator iterInstr = m_refTreeModel->append();
1284     Gtk::TreeModel::Row rowInstr = *iterInstr;
1285     rowInstr[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
1286     rowInstr[m_Columns.m_col_instr] = instrument;
1287 persson 1261 file_changed();
1288 schoenebeck 1225 }
1289    
1290     void MainWindow::on_action_remove_instrument() {
1291     if (!file) return;
1292 schoenebeck 1382 if (file_is_shared) {
1293     Gtk::MessageDialog msg(
1294     *this,
1295     _("You cannot delete an instrument from this file, since it's "
1296     "currently used by the sampler."),
1297     false, Gtk::MESSAGE_INFO
1298     );
1299     msg.run();
1300     return;
1301     }
1302    
1303 schoenebeck 1225 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
1304     Gtk::TreeModel::iterator it = sel->get_selected();
1305     if (it) {
1306     Gtk::TreeModel::Row row = *it;
1307     gig::Instrument* instr = row[m_Columns.m_col_instr];
1308     try {
1309     // remove instrument from the gig file
1310     if (instr) file->DeleteInstrument(instr);
1311     // remove respective row from instruments tree view
1312     m_refTreeModel->erase(it);
1313 persson 1261 file_changed();
1314 schoenebeck 1225 } catch (RIFF::Exception e) {
1315     Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1316     msg.run();
1317     }
1318     }
1319     }
1320    
1321     void MainWindow::on_action_sample_properties() {
1322     //TODO: show a dialog where the selected sample's properties can be edited
1323     Gtk::MessageDialog msg(
1324     *this, "Sorry, yet to be implemented!", false, Gtk::MESSAGE_INFO
1325     );
1326     msg.run();
1327     }
1328    
1329     void MainWindow::on_action_add_group() {
1330     static int __sample_indexer = 0;
1331     if (!file) return;
1332     gig::Group* group = file->AddGroup();
1333     group->Name = "Unnamed Group";
1334     if (__sample_indexer) group->Name += " " + ToString(__sample_indexer);
1335     __sample_indexer++;
1336     // update sample tree view
1337     Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
1338     Gtk::TreeModel::Row rowGroup = *iterGroup;
1339     rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1340     rowGroup[m_SamplesModel.m_col_sample] = NULL;
1341     rowGroup[m_SamplesModel.m_col_group] = group;
1342 persson 1261 file_changed();
1343 schoenebeck 1225 }
1344    
1345     void MainWindow::on_action_add_sample() {
1346     if (!file) return;
1347     // get selected group
1348     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1349     Gtk::TreeModel::iterator it = sel->get_selected();
1350     if (!it) return;
1351     Gtk::TreeModel::Row row = *it;
1352     gig::Group* group = row[m_SamplesModel.m_col_group];
1353     if (!group) { // not a group, but a sample is selected (probably)
1354     gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1355     if (!sample) return;
1356     it = row.parent(); // resolve parent (that is the sample's group)
1357     if (!it) return;
1358     row = *it;
1359     group = row[m_SamplesModel.m_col_group];
1360     if (!group) return;
1361     }
1362     // show 'browse for file' dialog
1363     Gtk::FileChooserDialog dialog(*this, _("Add Sample(s)"));
1364     dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1365     dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1366     dialog.set_select_multiple(true);
1367     Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile
1368 persson 1262 const char* const supportedFileTypes[] = {
1369 schoenebeck 1225 "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
1370     "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
1371     "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
1372     "*.W64", "*.pvf", "*.PVF", "*.xi", "*.XI", "*.htk", "*.HTK",
1373     "*.caf", "*.CAF", NULL
1374     };
1375     for (int i = 0; supportedFileTypes[i]; i++)
1376     soundfilter.add_pattern(supportedFileTypes[i]);
1377     soundfilter.set_name("Sound Files");
1378     Gtk::FileFilter allpassfilter; // matches every file
1379     allpassfilter.add_pattern("*.*");
1380     allpassfilter.set_name("All Files");
1381     dialog.add_filter(soundfilter);
1382     dialog.add_filter(allpassfilter);
1383     if (dialog.run() == Gtk::RESPONSE_OK) {
1384     Glib::ustring error_files;
1385     Glib::SListHandle<Glib::ustring> filenames = dialog.get_filenames();
1386     for (Glib::SListHandle<Glib::ustring>::iterator iter = filenames.begin();
1387     iter != filenames.end(); ++iter) {
1388     printf("Adding sample %s\n",(*iter).c_str());
1389     // use libsndfile to retrieve file informations
1390     SF_INFO info;
1391     info.format = 0;
1392     SNDFILE* hFile = sf_open((*iter).c_str(), SFM_READ, &info);
1393     try {
1394     if (!hFile) throw std::string("could not open file");
1395     int bitdepth;
1396     switch (info.format & 0xff) {
1397     case SF_FORMAT_PCM_S8:
1398     case SF_FORMAT_PCM_16:
1399 persson 1265 case SF_FORMAT_PCM_U8:
1400 schoenebeck 1225 bitdepth = 16;
1401     break;
1402     case SF_FORMAT_PCM_24:
1403     case SF_FORMAT_PCM_32:
1404     case SF_FORMAT_FLOAT:
1405     case SF_FORMAT_DOUBLE:
1406 persson 1265 bitdepth = 24;
1407 schoenebeck 1225 break;
1408     default:
1409     sf_close(hFile); // close sound file
1410     throw std::string("format not supported"); // unsupported subformat (yet?)
1411     }
1412     // add a new sample to the .gig file
1413     gig::Sample* sample = file->AddSample();
1414     // file name without path
1415 persson 1262 Glib::ustring filename = Glib::filename_display_basename(*iter);
1416     // remove file extension if there is one
1417     for (int i = 0; supportedFileTypes[i]; i++) {
1418     if (Glib::str_has_suffix(filename, supportedFileTypes[i] + 1)) {
1419     filename.erase(filename.length() - strlen(supportedFileTypes[i] + 1));
1420     break;
1421     }
1422     }
1423     sample->pInfo->Name = filename;
1424 schoenebeck 1225 sample->Channels = info.channels;
1425     sample->BitDepth = bitdepth;
1426     sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
1427     sample->SamplesPerSecond = info.samplerate;
1428 persson 1265 sample->AverageBytesPerSecond = sample->FrameSize * sample->SamplesPerSecond;
1429     sample->BlockAlign = sample->FrameSize;
1430     sample->SamplesTotal = info.frames;
1431    
1432     SF_INSTRUMENT instrument;
1433     if (sf_command(hFile, SFC_GET_INSTRUMENT,
1434     &instrument, sizeof(instrument)) != SF_FALSE)
1435     {
1436     sample->MIDIUnityNote = instrument.basenote;
1437    
1438 persson 1303 #if HAVE_SF_INSTRUMENT_LOOPS
1439 persson 1265 if (instrument.loop_count && instrument.loops[0].mode != SF_LOOP_NONE) {
1440     sample->Loops = 1;
1441    
1442     switch (instrument.loops[0].mode) {
1443     case SF_LOOP_FORWARD:
1444     sample->LoopType = gig::loop_type_normal;
1445     break;
1446     case SF_LOOP_BACKWARD:
1447     sample->LoopType = gig::loop_type_backward;
1448     break;
1449     case SF_LOOP_ALTERNATING:
1450     sample->LoopType = gig::loop_type_bidirectional;
1451     break;
1452     }
1453     sample->LoopStart = instrument.loops[0].start;
1454     sample->LoopEnd = instrument.loops[0].end;
1455     sample->LoopPlayCount = instrument.loops[0].count;
1456     sample->LoopSize = sample->LoopEnd - sample->LoopStart + 1;
1457     }
1458 persson 1303 #endif
1459 persson 1265 }
1460    
1461 schoenebeck 1225 // schedule resizing the sample (which will be done
1462     // physically when File::Save() is called)
1463     sample->Resize(info.frames);
1464     // make sure sample is part of the selected group
1465     group->AddSample(sample);
1466     // schedule that physical resize and sample import
1467     // (data copying), performed when "Save" is requested
1468     SampleImportItem sched_item;
1469     sched_item.gig_sample = sample;
1470     sched_item.sample_path = *iter;
1471     m_SampleImportQueue.push_back(sched_item);
1472     // add sample to the tree view
1473     Gtk::TreeModel::iterator iterSample =
1474     m_refSamplesTreeModel->append(row.children());
1475     Gtk::TreeModel::Row rowSample = *iterSample;
1476 persson 1262 rowSample[m_SamplesModel.m_col_name] = filename;
1477 schoenebeck 1225 rowSample[m_SamplesModel.m_col_sample] = sample;
1478     rowSample[m_SamplesModel.m_col_group] = NULL;
1479     // close sound file
1480     sf_close(hFile);
1481 persson 1261 file_changed();
1482 schoenebeck 1225 } catch (std::string what) { // remember the files that made trouble (and their cause)
1483     if (error_files.size()) error_files += "\n";
1484     error_files += *iter += " (" + what + ")";
1485     }
1486     }
1487     // show error message box when some file(s) could not be opened / added
1488     if (error_files.size()) {
1489 schoenebeck 1382 Glib::ustring txt = _("Could not add the following sample(s):\n") + error_files;
1490 schoenebeck 1225 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1491     msg.run();
1492     }
1493     }
1494     }
1495    
1496     void MainWindow::on_action_remove_sample() {
1497     if (!file) return;
1498     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1499     Gtk::TreeModel::iterator it = sel->get_selected();
1500     if (it) {
1501     Gtk::TreeModel::Row row = *it;
1502     gig::Group* group = row[m_SamplesModel.m_col_group];
1503     gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1504     Glib::ustring name = row[m_SamplesModel.m_col_name];
1505     try {
1506     // remove group or sample from the gig file
1507     if (group) {
1508     // temporarily remember the samples that bolong to
1509     // that group (we need that to clean the queue)
1510     std::list<gig::Sample*> members;
1511     for (gig::Sample* pSample = group->GetFirstSample();
1512     pSample; pSample = group->GetNextSample()) {
1513     members.push_back(pSample);
1514     }
1515 schoenebeck 1322 // notify everybody that we're going to remove these samples
1516     samples_to_be_removed_signal.emit(members);
1517 schoenebeck 1225 // delete the group in the .gig file including the
1518     // samples that belong to the group
1519     file->DeleteGroup(group);
1520 schoenebeck 1322 // notify that we're done with removal
1521     samples_removed_signal.emit();
1522 schoenebeck 1225 // if sample(s) were just previously added, remove
1523     // them from the import queue
1524     for (std::list<gig::Sample*>::iterator member = members.begin();
1525     member != members.end(); ++member) {
1526     for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
1527     iter != m_SampleImportQueue.end(); ++iter) {
1528     if ((*iter).gig_sample == *member) {
1529     printf("Removing previously added sample '%s' from group '%s'\n",
1530     (*iter).sample_path.c_str(), name.c_str());
1531     m_SampleImportQueue.erase(iter);
1532     break;
1533     }
1534     }
1535     }
1536 persson 1261 file_changed();
1537 schoenebeck 1225 } else if (sample) {
1538 schoenebeck 1322 // notify everybody that we're going to remove this sample
1539     std::list<gig::Sample*> lsamples;
1540     lsamples.push_back(sample);
1541     samples_to_be_removed_signal.emit(lsamples);
1542 schoenebeck 1225 // remove sample from the .gig file
1543     file->DeleteSample(sample);
1544 schoenebeck 1322 // notify that we're done with removal
1545     samples_removed_signal.emit();
1546 schoenebeck 1225 // if sample was just previously added, remove it from
1547     // the import queue
1548     for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
1549     iter != m_SampleImportQueue.end(); ++iter) {
1550     if ((*iter).gig_sample == sample) {
1551     printf("Removing previously added sample '%s'\n",
1552     (*iter).sample_path.c_str());
1553     m_SampleImportQueue.erase(iter);
1554     break;
1555     }
1556     }
1557 persson 1303 dimreg_changed();
1558 persson 1261 file_changed();
1559 schoenebeck 1225 }
1560     // remove respective row(s) from samples tree view
1561     m_refSamplesTreeModel->erase(it);
1562     } catch (RIFF::Exception e) {
1563 schoenebeck 1322 // pretend we're done with removal (i.e. to avoid dead locks)
1564     samples_removed_signal.emit();
1565     // show error message
1566 schoenebeck 1225 Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1567     msg.run();
1568     }
1569     }
1570     }
1571    
1572 persson 1303 // For some reason drag_data_get gets called two times for each
1573     // drag'n'drop (at least when target is an Entry). This work-around
1574     // makes sure the code in drag_data_get and drop_drag_data_received is
1575     // only executed once, as drag_begin only gets called once.
1576     void MainWindow::on_sample_treeview_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context)
1577     {
1578     first_call_to_drag_data_get = true;
1579     }
1580    
1581 schoenebeck 1225 void MainWindow::on_sample_treeview_drag_data_get(const Glib::RefPtr<Gdk::DragContext>&,
1582     Gtk::SelectionData& selection_data, guint, guint)
1583     {
1584 persson 1303 if (!first_call_to_drag_data_get) return;
1585     first_call_to_drag_data_get = false;
1586    
1587 schoenebeck 1225 // get selected sample
1588     gig::Sample* sample = NULL;
1589     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1590     Gtk::TreeModel::iterator it = sel->get_selected();
1591     if (it) {
1592     Gtk::TreeModel::Row row = *it;
1593     sample = row[m_SamplesModel.m_col_sample];
1594     }
1595     // pass the gig::Sample as pointer
1596     selection_data.set(selection_data.get_target(), 0/*unused*/, (const guchar*)&sample,
1597     sizeof(sample)/*length of data in bytes*/);
1598     }
1599    
1600     void MainWindow::on_sample_label_drop_drag_data_received(
1601     const Glib::RefPtr<Gdk::DragContext>& context, int, int,
1602     const Gtk::SelectionData& selection_data, guint, guint time)
1603     {
1604     gig::Sample* sample = *((gig::Sample**) selection_data.get_data());
1605    
1606 persson 1265 if (sample && selection_data.get_length() == sizeof(gig::Sample*)) {
1607 persson 1303 std::cout << "Drop received sample \"" <<
1608     sample->pInfo->Name << "\"" << std::endl;
1609     // drop success
1610     context->drop_reply(true, time);
1611    
1612 schoenebeck 1322 //TODO: we should better move most of the following code to DimRegionEdit::set_sample()
1613    
1614     // notify everybody that we're going to alter the region
1615     gig::Region* region = m_RegionChooser.get_region();
1616     region_to_be_changed_signal.emit(region);
1617    
1618 persson 1303 // find the samplechannel dimension
1619     gig::dimension_def_t* stereo_dimension = 0;
1620     for (int i = 0 ; i < region->Dimensions ; i++) {
1621     if (region->pDimensionDefinitions[i].dimension ==
1622     gig::dimension_samplechannel) {
1623     stereo_dimension = &region->pDimensionDefinitions[i];
1624     break;
1625     }
1626 schoenebeck 1225 }
1627 persson 1303 bool channels_changed = false;
1628     if (sample->Channels == 1 && stereo_dimension) {
1629     // remove the samplechannel dimension
1630     region->DeleteDimension(stereo_dimension);
1631     channels_changed = true;
1632     region_changed();
1633     }
1634     dimreg_edit.set_sample(sample);
1635    
1636     if (sample->Channels == 2 && !stereo_dimension) {
1637     // add samplechannel dimension
1638     gig::dimension_def_t dim;
1639     dim.dimension = gig::dimension_samplechannel;
1640     dim.bits = 1;
1641     dim.zones = 2;
1642     region->AddDimension(&dim);
1643     channels_changed = true;
1644     region_changed();
1645     }
1646     if (channels_changed) {
1647     // unmap all samples with wrong number of channels
1648     // TODO: maybe there should be a warning dialog for this
1649     for (int i = 0 ; i < region->DimensionRegions ; i++) {
1650     gig::DimensionRegion* d = region->pDimensionRegions[i];
1651     if (d->pSample && d->pSample->Channels != sample->Channels) {
1652 schoenebeck 1322 gig::Sample* oldref = d->pSample;
1653     d->pSample = NULL;
1654     sample_ref_changed_signal.emit(oldref, NULL);
1655 persson 1303 }
1656     }
1657     }
1658    
1659 schoenebeck 1322 // notify we're done with altering
1660     region_changed_signal.emit(region);
1661    
1662 persson 1460 file_changed();
1663    
1664 persson 1303 return;
1665 schoenebeck 1225 }
1666     // drop failed
1667     context->drop_reply(false, time);
1668     }
1669    
1670     void MainWindow::sample_name_changed(const Gtk::TreeModel::Path& path,
1671     const Gtk::TreeModel::iterator& iter) {
1672     if (!iter) return;
1673     Gtk::TreeModel::Row row = *iter;
1674     Glib::ustring name = row[m_SamplesModel.m_col_name];
1675     gig::Group* group = row[m_SamplesModel.m_col_group];
1676     gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1677     if (group) {
1678 persson 1261 if (group->Name != name) {
1679     group->Name = name;
1680     printf("group name changed\n");
1681     file_changed();
1682     }
1683 schoenebeck 1225 } else if (sample) {
1684 persson 1261 if (sample->pInfo->Name != name.raw()) {
1685     sample->pInfo->Name = name.raw();
1686     printf("sample name changed\n");
1687     file_changed();
1688     }
1689 schoenebeck 1225 }
1690     }
1691    
1692     void MainWindow::instrument_name_changed(const Gtk::TreeModel::Path& path,
1693     const Gtk::TreeModel::iterator& iter) {
1694     if (!iter) return;
1695     Gtk::TreeModel::Row row = *iter;
1696     Glib::ustring name = row[m_Columns.m_col_name];
1697     gig::Instrument* instrument = row[m_Columns.m_col_instr];
1698 persson 1261 if (instrument && instrument->pInfo->Name != name.raw()) {
1699     instrument->pInfo->Name = name.raw();
1700     file_changed();
1701     }
1702 schoenebeck 1225 }
1703 schoenebeck 1322
1704 schoenebeck 1411 void MainWindow::set_file_is_shared(bool b) {
1705     this->file_is_shared = b;
1706    
1707     if (file_is_shared) {
1708     m_AttachedStateLabel.set_label(_("live-mode"));
1709     m_AttachedStateImage.set(
1710     Gdk::Pixbuf::create_from_xpm_data(status_attached_xpm)
1711     );
1712     } else {
1713     m_AttachedStateLabel.set_label(_("stand-alone"));
1714     m_AttachedStateImage.set(
1715     Gdk::Pixbuf::create_from_xpm_data(status_detached_xpm)
1716     );
1717     }
1718     }
1719    
1720 schoenebeck 1339 sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_to_be_changed() {
1721 schoenebeck 1322 return file_structure_to_be_changed_signal;
1722     }
1723    
1724 schoenebeck 1339 sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_changed() {
1725 schoenebeck 1322 return file_structure_changed_signal;
1726     }
1727    
1728 schoenebeck 1339 sigc::signal<void, std::list<gig::Sample*> >& MainWindow::signal_samples_to_be_removed() {
1729 schoenebeck 1322 return samples_to_be_removed_signal;
1730     }
1731    
1732 schoenebeck 1339 sigc::signal<void>& MainWindow::signal_samples_removed() {
1733 schoenebeck 1322 return samples_removed_signal;
1734     }
1735    
1736 schoenebeck 1339 sigc::signal<void, gig::Region*>& MainWindow::signal_region_to_be_changed() {
1737 schoenebeck 1322 return region_to_be_changed_signal;
1738     }
1739    
1740 schoenebeck 1339 sigc::signal<void, gig::Region*>& MainWindow::signal_region_changed() {
1741 schoenebeck 1322 return region_changed_signal;
1742     }
1743    
1744 schoenebeck 1339 sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& MainWindow::signal_sample_ref_changed() {
1745 schoenebeck 1322 return sample_ref_changed_signal;
1746     }
1747    
1748 schoenebeck 1339 sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_to_be_changed() {
1749 schoenebeck 1322 return dimreg_to_be_changed_signal;
1750     }
1751    
1752 schoenebeck 1339 sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_changed() {
1753 schoenebeck 1322 return dimreg_changed_signal;
1754     }
1755 schoenebeck 1654
1756     sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_note_on() {
1757     return note_on_signal;
1758     }
1759    
1760     sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_note_off() {
1761     return note_off_signal;
1762     }
1763 schoenebeck 1660
1764     sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_keyboard_key_hit() {
1765     return m_RegionChooser.signal_keyboard_key_hit();
1766     }
1767    
1768     sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_keyboard_key_released() {
1769     return m_RegionChooser.signal_keyboard_key_released();
1770     }

  ViewVC Help
Powered by ViewVC