/[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 1660 - (hide annotations) (download)
Sun Feb 3 00:19:55 2008 UTC (16 years, 1 month ago) by schoenebeck
File size: 64795 byte(s)
* call it virtually baby: the keyboard finally can trigger notes on
  sampler side (only in live-mode of course)
* added a red cross on top of the detached-mode icon to make
  it more obvious

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

  ViewVC Help
Powered by ViewVC