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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1300 - (show annotations) (download)
Fri Aug 24 19:11:41 2007 UTC (16 years, 7 months ago) by schoenebeck
File size: 48825 byte(s)
* start with a new gig file by default
* fixed minor compilation error

1 /*
2 * Copyright (C) 2006, 2007 Andreas Persson
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2, or (at
7 * your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with program; see the file COPYING. If not, write to the Free
16 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17 * 02110-1301 USA.
18 */
19
20 #include <libintl.h>
21 #include <iostream>
22
23 #include <gtkmm/filechooserdialog.h>
24 #include <gtkmm/messagedialog.h>
25 #include <gtkmm/stock.h>
26 #include <gtkmm/targetentry.h>
27 #include <gtkmm/main.h>
28
29 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
30 #define ABOUT_DIALOG
31 #include <gtkmm/aboutdialog.h>
32 #endif
33
34 #include <stdio.h>
35 #include <sndfile.h>
36
37 #include "mainwindow.h"
38
39 #define _(String) gettext(String)
40
41 template<class T> inline std::string ToString(T o) {
42 std::stringstream ss;
43 ss << o;
44 return ss.str();
45 }
46
47 MainWindow::MainWindow()
48 {
49 // set_border_width(5);
50 // set_default_size(400, 200);
51
52
53 add(m_VBox);
54
55 // Handle selection
56 Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
57 tree_sel_ref->signal_changed().connect(
58 sigc::mem_fun(*this, &MainWindow::on_sel_change));
59
60 // m_TreeView.set_reorderable();
61
62 m_TreeView.signal_button_press_event().connect_notify(
63 sigc::mem_fun(*this, &MainWindow::on_button_release));
64
65 // Add the TreeView tab, inside a ScrolledWindow, with the button underneath:
66 m_ScrolledWindow.add(m_TreeView);
67 // m_ScrolledWindow.set_size_request(200, 600);
68 m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
69
70 m_ScrolledWindowSamples.add(m_TreeViewSamples);
71 m_ScrolledWindowSamples.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
72
73
74 m_TreeViewNotebook.set_size_request(300);
75
76 m_HPaned.add1(m_TreeViewNotebook);
77 m_HPaned.add2(dimreg_edit);
78
79
80 m_TreeViewNotebook.append_page(m_ScrolledWindowSamples, "Samples");
81 m_TreeViewNotebook.append_page(m_ScrolledWindow, "Instruments");
82
83
84 actionGroup = Gtk::ActionGroup::create();
85
86 actionGroup->add(Gtk::Action::create("MenuFile", _("_File")));
87 actionGroup->add(Gtk::Action::create("New", Gtk::Stock::NEW),
88 sigc::mem_fun(
89 *this, &MainWindow::on_action_file_new));
90 Glib::RefPtr<Gtk::Action> action =
91 Gtk::Action::create("Open", Gtk::Stock::OPEN);
92 action->property_label() = action->property_label() + "...";
93 actionGroup->add(action,
94 sigc::mem_fun(
95 *this, &MainWindow::on_action_file_open));
96 actionGroup->add(Gtk::Action::create("Save", Gtk::Stock::SAVE),
97 sigc::mem_fun(
98 *this, &MainWindow::on_action_file_save));
99 action = Gtk::Action::create("SaveAs", Gtk::Stock::SAVE_AS);
100 action->property_label() = action->property_label() + "...";
101 actionGroup->add(action,
102 Gtk::AccelKey("<shift><control>s"),
103 sigc::mem_fun(
104 *this, &MainWindow::on_action_file_save_as));
105 actionGroup->add(Gtk::Action::create("Properties",
106 Gtk::Stock::PROPERTIES),
107 sigc::mem_fun(
108 *this, &MainWindow::on_action_file_properties));
109 actionGroup->add(Gtk::Action::create("InstrProperties",
110 Gtk::Stock::PROPERTIES),
111 sigc::mem_fun(
112 *this, &MainWindow::show_instr_props));
113 actionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT),
114 sigc::mem_fun(
115 *this, &MainWindow::on_action_quit));
116 actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));
117
118 action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);
119 actionGroup->add(Gtk::Action::create("MenuHelp",
120 action->property_label()));
121 #ifdef ABOUT_DIALOG
122 actionGroup->add(Gtk::Action::create("About", Gtk::Stock::ABOUT),
123 sigc::mem_fun(
124 *this, &MainWindow::on_action_help_about));
125 #endif
126 actionGroup->add(
127 Gtk::Action::create("AddInstrument", _("Add _Instrument")),
128 sigc::mem_fun(*this, &MainWindow::on_action_add_instrument)
129 );
130 actionGroup->add(
131 Gtk::Action::create("RemoveInstrument", Gtk::Stock::REMOVE),
132 sigc::mem_fun(*this, &MainWindow::on_action_remove_instrument)
133 );
134
135 // sample right-click popup actions
136 actionGroup->add(
137 Gtk::Action::create("SampleProperties", Gtk::Stock::PROPERTIES),
138 sigc::mem_fun(*this, &MainWindow::on_action_sample_properties)
139 );
140 actionGroup->add(
141 Gtk::Action::create("AddGroup", _("Add _Group")),
142 sigc::mem_fun(*this, &MainWindow::on_action_add_group)
143 );
144 actionGroup->add(
145 Gtk::Action::create("AddSample", _("Add _Sample(s)")),
146 sigc::mem_fun(*this, &MainWindow::on_action_add_sample)
147 );
148 actionGroup->add(
149 Gtk::Action::create("RemoveSample", Gtk::Stock::REMOVE),
150 sigc::mem_fun(*this, &MainWindow::on_action_remove_sample)
151 );
152
153 uiManager = Gtk::UIManager::create();
154 uiManager->insert_action_group(actionGroup);
155 add_accel_group(uiManager->get_accel_group());
156
157 Glib::ustring ui_info =
158 "<ui>"
159 " <menubar name='MenuBar'>"
160 " <menu action='MenuFile'>"
161 " <menuitem action='New'/>"
162 " <menuitem action='Open'/>"
163 " <separator/>"
164 " <menuitem action='Save'/>"
165 " <menuitem action='SaveAs'/>"
166 " <separator/>"
167 " <menuitem action='Properties'/>"
168 " <separator/>"
169 " <menuitem action='Quit'/>"
170 " </menu>"
171 " <menu action='MenuInstrument'>"
172 " </menu>"
173 #ifdef ABOUT_DIALOG
174 " <menu action='MenuHelp'>"
175 " <menuitem action='About'/>"
176 " </menu>"
177 #endif
178 " </menubar>"
179 " <popup name='PopupMenu'>"
180 " <menuitem action='InstrProperties'/>"
181 " <menuitem action='AddInstrument'/>"
182 " <separator/>"
183 " <menuitem action='RemoveInstrument'/>"
184 " </popup>"
185 " <popup name='SamplePopupMenu'>"
186 " <menuitem action='SampleProperties'/>"
187 " <menuitem action='AddGroup'/>"
188 " <menuitem action='AddSample'/>"
189 " <separator/>"
190 " <menuitem action='RemoveSample'/>"
191 " </popup>"
192 "</ui>";
193 uiManager->add_ui_from_string(ui_info);
194
195 popup_menu = dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/PopupMenu"));
196
197 Gtk::Widget* menuBar = uiManager->get_widget("/MenuBar");
198 m_VBox.pack_start(*menuBar, Gtk::PACK_SHRINK);
199 m_VBox.pack_start(m_HPaned);
200 m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);
201 m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);
202
203 m_RegionChooser.signal_region_selected().connect(
204 sigc::mem_fun(*this, &MainWindow::region_changed) );
205 m_DimRegionChooser.signal_dimregion_selected().connect(
206 sigc::mem_fun(*this, &MainWindow::dimreg_changed) );
207
208
209 // Create the Tree model:
210 m_refTreeModel = Gtk::ListStore::create(m_Columns);
211 m_TreeView.set_model(m_refTreeModel);
212 m_refTreeModel->signal_row_changed().connect(
213 sigc::mem_fun(*this, &MainWindow::instrument_name_changed)
214 );
215
216 // Add the TreeView's view columns:
217 m_TreeView.append_column_editable("Instrument", m_Columns.m_col_name);
218 m_TreeView.set_headers_visible(false);
219
220 // create samples treeview (including its data model)
221 m_refSamplesTreeModel = SamplesTreeStore::create(m_SamplesModel);
222 m_TreeViewSamples.set_model(m_refSamplesTreeModel);
223 // m_TreeViewSamples.set_reorderable();
224 m_TreeViewSamples.append_column_editable("Samples", m_SamplesModel.m_col_name);
225 m_TreeViewSamples.set_headers_visible(false);
226 m_TreeViewSamples.signal_button_press_event().connect_notify(
227 sigc::mem_fun(*this, &MainWindow::on_sample_treeview_button_release)
228 );
229 m_refSamplesTreeModel->signal_row_changed().connect(
230 sigc::mem_fun(*this, &MainWindow::sample_name_changed)
231 );
232
233 // establish drag&drop between samples tree view and dimension region 'Sample' text entry
234 std::list<Gtk::TargetEntry> drag_target_gig_sample;
235 drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );
236 m_TreeViewSamples.drag_source_set(drag_target_gig_sample);
237 m_TreeViewSamples.signal_drag_data_get().connect(
238 sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)
239 );
240 dimreg_edit.wSample->drag_dest_set(drag_target_gig_sample);
241 dimreg_edit.wSample->signal_drag_data_received().connect(
242 sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)
243 );
244 dimreg_edit.signal_dimreg_changed().connect(
245 sigc::mem_fun(*this, &MainWindow::file_changed));
246 m_RegionChooser.signal_instrument_changed().connect(
247 sigc::mem_fun(*this, &MainWindow::file_changed));
248 m_DimRegionChooser.signal_region_changed().connect(
249 sigc::mem_fun(*this, &MainWindow::file_changed));
250 instrumentProps.signal_instrument_changed().connect(
251 sigc::mem_fun(*this, &MainWindow::file_changed));
252 file = 0;
253 file_is_changed = false;
254
255 show_all_children();
256
257 // start with a new gig file by default
258 on_action_file_new();
259 }
260
261 MainWindow::~MainWindow()
262 {
263 }
264
265 bool MainWindow::on_delete_event(GdkEventAny* event)
266 {
267 return file_is_changed && !close_confirmation_dialog();
268 }
269
270 void MainWindow::on_action_quit()
271 {
272 if (file_is_changed && !close_confirmation_dialog()) return;
273 hide();
274 }
275
276 void MainWindow::region_changed()
277 {
278 m_DimRegionChooser.set_region(m_RegionChooser.get_region());
279 }
280
281 void MainWindow::dimreg_changed()
282 {
283 dimreg_edit.set_dim_region(m_DimRegionChooser.get_dimregion());
284 }
285
286 void MainWindow::on_sel_change()
287 {
288 Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
289
290 Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
291 if (it) {
292 Gtk::TreeModel::Row row = *it;
293 std::cout << row[m_Columns.m_col_name] << std::endl;
294
295 m_RegionChooser.set_instrument(row[m_Columns.m_col_instr]);
296 } else {
297 m_RegionChooser.set_instrument(0);
298 }
299 }
300
301 void loader_progress_callback(gig::progress_t* progress)
302 {
303 Loader* loader = static_cast<Loader*>(progress->custom);
304 loader->progress_callback(progress->factor);
305 }
306
307 void Loader::progress_callback(float fraction)
308 {
309 {
310 Glib::Mutex::Lock lock(progressMutex);
311 progress = fraction;
312 }
313 progress_dispatcher();
314 }
315
316 void Loader::thread_function()
317 {
318 printf("thread_function self=%x\n", Glib::Thread::self());
319 printf("Start %s\n", filename);
320 RIFF::File* riff = new RIFF::File(filename);
321 gig = new gig::File(riff);
322 gig::progress_t progress;
323 progress.callback = loader_progress_callback;
324 progress.custom = this;
325
326 gig->GetInstrument(0, &progress);
327 printf("End\n");
328 finished_dispatcher();
329 }
330
331 Loader::Loader(const char* filename)
332 : thread(0), filename(filename)
333 {
334 }
335
336 void Loader::launch()
337 {
338 thread = Glib::Thread::create(sigc::mem_fun(*this, &Loader::thread_function), true);
339 printf("launch thread=%x\n", thread);
340 }
341
342 float Loader::get_progress()
343 {
344 float res;
345 {
346 Glib::Mutex::Lock lock(progressMutex);
347 res = progress;
348 }
349 return res;
350 }
351
352 Glib::Dispatcher& Loader::signal_progress()
353 {
354 return progress_dispatcher;
355 }
356
357 Glib::Dispatcher& Loader::signal_finished()
358 {
359 return finished_dispatcher;
360 }
361
362 LoadDialog::LoadDialog(const Glib::ustring& title, Gtk::Window& parent)
363 : Gtk::Dialog(title, parent, true)
364 {
365 get_vbox()->pack_start(progressBar);
366 show_all_children();
367 }
368
369 // Clear all GUI elements / controls. This method is typically called
370 // before a new .gig file is to be created or to be loaded.
371 void MainWindow::__clear() {
372 // remove all entries from "Instrument" menu
373 Gtk::MenuItem* instrument_menu =
374 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));
375 instrument_menu->hide();
376 for (int i = 0; i < instrument_menu->get_submenu()->items().size(); i++) {
377 delete &instrument_menu->get_submenu()->items()[i];
378 }
379 instrument_menu->get_submenu()->items().clear();
380 // forget all samples that ought to be imported
381 m_SampleImportQueue.clear();
382 // clear the samples and instruments tree views
383 m_refTreeModel->clear();
384 m_refSamplesTreeModel->clear();
385 // free libgig's gig::File instance
386 if (file) {
387 delete file;
388 file = NULL;
389 }
390 }
391
392 void MainWindow::on_action_file_new()
393 {
394 if (file_is_changed && !close_confirmation_dialog()) return;
395
396 // clear all GUI elements
397 __clear();
398 // create a new .gig file (virtually yet)
399 gig::File* pFile = new gig::File;
400 // already add one new instrument by default
401 gig::Instrument* pInstrument = pFile->AddInstrument();
402 pInstrument->pInfo->Name = "Unnamed Instrument";
403 // update GUI with that new gig::File
404 load_gig(pFile, 0 /*no file name yet*/);
405 }
406
407 bool MainWindow::close_confirmation_dialog()
408 {
409 gchar* msg = g_strdup_printf(_("Save changes to \"%s\" before closing?"),
410 Glib::filename_display_basename(filename).c_str());
411 Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
412 g_free(msg);
413 dialog.set_secondary_text(_("If you close without saving, your changes will be lost."));
414 dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);
415 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
416 dialog.add_button(file_has_name ? Gtk::Stock::SAVE : Gtk::Stock::SAVE_AS, Gtk::RESPONSE_YES);
417 dialog.set_default_response(Gtk::RESPONSE_YES);
418 int response = dialog.run();
419 if (response == Gtk::RESPONSE_YES) return file_save();
420 return response != Gtk::RESPONSE_CANCEL;
421 }
422
423 void MainWindow::on_action_file_open()
424 {
425 if (file_is_changed && !close_confirmation_dialog()) return;
426
427 Gtk::FileChooserDialog dialog(*this, _("Open file"));
428 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
429 dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
430 dialog.set_default_response(Gtk::RESPONSE_OK);
431 Gtk::FileFilter filter;
432 filter.add_pattern("*.gig");
433 dialog.set_filter(filter);
434 if (current_dir != "") {
435 dialog.set_current_folder(current_dir);
436 }
437 if (dialog.run() == Gtk::RESPONSE_OK) {
438 std::string filename = dialog.get_filename();
439 printf("filename=%s\n", filename.c_str());
440 __clear();
441 printf("on_action_file_open self=%x\n", Glib::Thread::self());
442 load_file(filename.c_str());
443 current_dir = Glib::path_get_dirname(filename);
444 }
445 }
446
447 void MainWindow::load_file(const char* name)
448 {
449 load_dialog = new LoadDialog("Loading...", *this);
450 load_dialog->show_all();
451 loader = new Loader(strdup(name));
452 loader->signal_progress().connect(
453 sigc::mem_fun(*this, &MainWindow::on_loader_progress));
454 loader->signal_finished().connect(
455 sigc::mem_fun(*this, &MainWindow::on_loader_finished));
456 loader->launch();
457 }
458
459 void MainWindow::load_instrument(gig::Instrument* instr) {
460 if (!instr) {
461 Glib::ustring txt = "Provided instrument is NULL!\n";
462 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
463 msg.run();
464 Gtk::Main::quit();
465 }
466 gig::File* pFile = (gig::File*) instr->GetParent();
467 load_gig(pFile, 0 /*file name*/);
468 //TODO: automatically select the given instrument
469 }
470
471 void MainWindow::on_loader_progress()
472 {
473 load_dialog->set_fraction(loader->get_progress());
474 }
475
476 void MainWindow::on_loader_finished()
477 {
478 printf("Loader finished!\n");
479 printf("on_loader_finished self=%x\n", Glib::Thread::self());
480 load_gig(loader->gig, loader->filename);
481 load_dialog->hide();
482 }
483
484 void MainWindow::on_action_file_save()
485 {
486 file_save();
487 }
488
489 bool MainWindow::file_save()
490 {
491 if (!file) return false;
492 if (!file_has_name) return file_save_as();
493
494 std::cout << "Saving file\n" << std::flush;
495 try {
496 file->Save();
497 if (file_is_changed) {
498 set_title(get_title().substr(1));
499 file_is_changed = false;
500 }
501 } catch (RIFF::Exception e) {
502 Glib::ustring txt = "Could not save file: " + e.Message;
503 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
504 msg.run();
505 return false;
506 }
507 std::cout << "Saving file done\n" << std::flush;
508 __import_queued_samples();
509 return true;
510 }
511
512 void MainWindow::on_action_file_save_as()
513 {
514 file_save_as();
515 }
516
517 bool MainWindow::file_save_as()
518 {
519 if (!file) return false;
520 Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE);
521 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
522 dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
523 dialog.set_default_response(Gtk::RESPONSE_OK);
524
525 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 8) || GTKMM_MAJOR_VERSION > 2
526 dialog.set_do_overwrite_confirmation();
527 // TODO: an overwrite dialog for gtkmm < 2.8
528 #endif
529 Gtk::FileFilter filter;
530 filter.add_pattern("*.gig");
531 dialog.set_filter(filter);
532
533 if (Glib::path_is_absolute(filename)) {
534 dialog.set_filename(filename);
535 } else if (current_dir != "") {
536 dialog.set_current_folder(current_dir);
537 }
538 dialog.set_current_name(Glib::filename_display_basename(filename));
539
540 if (dialog.run() == Gtk::RESPONSE_OK) {
541 try {
542 std::string filename = dialog.get_filename();
543 if (!Glib::str_has_suffix(filename, ".gig")) {
544 filename += ".gig";
545 }
546 printf("filename=%s\n", filename.c_str());
547 file->Save(filename);
548 this->filename = filename;
549 current_dir = Glib::path_get_dirname(filename);
550 set_title(Glib::filename_display_basename(filename));
551 file_has_name = true;
552 file_is_changed = false;
553 } catch (RIFF::Exception e) {
554 Glib::ustring txt = "Could not save file: " + e.Message;
555 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
556 msg.run();
557 return false;
558 }
559 __import_queued_samples();
560 return true;
561 }
562 return false;
563 }
564
565 // actually write the sample(s)' data to the gig file
566 void MainWindow::__import_queued_samples() {
567 std::cout << "Starting sample import\n" << std::flush;
568 Glib::ustring error_files;
569 printf("Samples to import: %d\n", m_SampleImportQueue.size());
570 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
571 iter != m_SampleImportQueue.end(); ) {
572 printf("Importing sample %s\n",(*iter).sample_path.c_str());
573 SF_INFO info;
574 info.format = 0;
575 SNDFILE* hFile = sf_open((*iter).sample_path.c_str(), SFM_READ, &info);
576 try {
577 if (!hFile) throw std::string("could not open file");
578 // determine sample's bit depth
579 int bitdepth;
580 switch (info.format & 0xff) {
581 case SF_FORMAT_PCM_S8:
582 case SF_FORMAT_PCM_16:
583 case SF_FORMAT_PCM_U8:
584 bitdepth = 16;
585 break;
586 case SF_FORMAT_PCM_24:
587 case SF_FORMAT_PCM_32:
588 case SF_FORMAT_FLOAT:
589 case SF_FORMAT_DOUBLE:
590 bitdepth = 24;
591 break;
592 default:
593 sf_close(hFile); // close sound file
594 throw std::string("format not supported"); // unsupported subformat (yet?)
595 }
596
597 const int bufsize = 10000;
598 switch (bitdepth) {
599 case 16: {
600 short* buffer = new short[bufsize * info.channels];
601 sf_count_t cnt = info.frames;
602 while (cnt) {
603 // libsndfile does the conversion for us (if needed)
604 int n = sf_readf_short(hFile, buffer, bufsize);
605 // write from buffer directly (physically) into .gig file
606 iter->gig_sample->Write(buffer, n);
607 cnt -= n;
608 }
609 delete[] buffer;
610 break;
611 }
612 case 24: {
613 int* srcbuf = new int[bufsize * info.channels];
614 uint8_t* dstbuf = new uint8_t[bufsize * 3 * info.channels];
615 sf_count_t cnt = info.frames;
616 while (cnt) {
617 // libsndfile returns 32 bits, convert to 24
618 int n = sf_readf_int(hFile, srcbuf, bufsize);
619 int j = 0;
620 for (int i = 0 ; i < n * info.channels ; i++) {
621 dstbuf[j++] = srcbuf[i] >> 8;
622 dstbuf[j++] = srcbuf[i] >> 16;
623 dstbuf[j++] = srcbuf[i] >> 24;
624 }
625 // write from buffer directly (physically) into .gig file
626 iter->gig_sample->Write(dstbuf, n);
627 cnt -= n;
628 }
629 delete[] srcbuf;
630 delete[] dstbuf;
631 break;
632 }
633 }
634 // cleanup
635 sf_close(hFile);
636 // on success we remove the sample from the import queue,
637 // otherwise keep it, maybe it works the next time ?
638 std::list<SampleImportItem>::iterator cur = iter;
639 ++iter;
640 m_SampleImportQueue.erase(cur);
641 } catch (std::string what) {
642 // remember the files that made trouble (and their cause)
643 if (error_files.size()) error_files += "\n";
644 error_files += (*iter).sample_path += " (" + what + ")";
645 ++iter;
646 }
647 }
648 // show error message box when some sample(s) could not be imported
649 if (error_files.size()) {
650 Glib::ustring txt = "Could not import the following sample(s):\n" + error_files;
651 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
652 msg.run();
653 }
654 }
655
656 void MainWindow::on_action_file_properties()
657 {
658 propDialog.show();
659 propDialog.deiconify();
660 }
661
662 void MainWindow::on_action_help_about()
663 {
664 #ifdef ABOUT_DIALOG
665 Gtk::AboutDialog dialog;
666 dialog.set_version(VERSION);
667 dialog.run();
668 #endif
669 }
670
671 PropDialog::PropDialog()
672 : table(2,1)
673 {
674 table.set_col_spacings(5);
675 const char* propLabels[] = {
676 "Name:",
677 "CreationDate:",
678 "Comments:", // TODO: multiline
679 "Product:",
680 "Copyright:",
681 "Artists:",
682 "Genre:",
683 "Keywords:",
684 "Engineer:",
685 "Technician:",
686 "Software:", // TODO: readonly
687 "Medium:",
688 "Source:",
689 "SourceForm:",
690 "Commissioned:",
691 "Subject:"
692 };
693 for (int i = 0 ; i < sizeof(propLabels) / sizeof(char*) ; i++) {
694 label[i].set_text(propLabels[i]);
695 label[i].set_alignment(Gtk::ALIGN_LEFT);
696 table.attach(label[i], 0, 1, i, i + 1, Gtk::FILL, Gtk::SHRINK);
697 table.attach(entry[i], 1, 2, i, i + 1, Gtk::FILL | Gtk::EXPAND,
698 Gtk::SHRINK);
699 }
700
701 add(table);
702 // add_button(Gtk::Stock::CANCEL, 0);
703 // add_button(Gtk::Stock::OK, 1);
704 show_all_children();
705 }
706
707 void PropDialog::set_info(DLS::Info* info)
708 {
709 entry[0].set_text(info->Name);
710 entry[1].set_text(info->CreationDate);
711 entry[2].set_text(Glib::convert(info->Comments, "UTF-8", "ISO-8859-1"));
712 entry[3].set_text(info->Product);
713 entry[4].set_text(info->Copyright);
714 entry[5].set_text(info->Artists);
715 entry[6].set_text(info->Genre);
716 entry[7].set_text(info->Keywords);
717 entry[8].set_text(info->Engineer);
718 entry[9].set_text(info->Technician);
719 entry[10].set_text(info->Software);
720 entry[11].set_text(info->Medium);
721 entry[12].set_text(info->Source);
722 entry[13].set_text(info->SourceForm);
723 entry[14].set_text(info->Commissioned);
724 entry[15].set_text(info->Subject);
725 }
726
727 void InstrumentProps::add_prop(BoolEntry& boolentry)
728 {
729 table.attach(boolentry.widget, 0, 2, rowno, rowno + 1,
730 Gtk::FILL, Gtk::SHRINK);
731 rowno++;
732 boolentry.signal_changed_by_user().connect(instrument_changed.make_slot());
733 }
734
735 void InstrumentProps::add_prop(BoolEntryPlus6& boolentry)
736 {
737 table.attach(boolentry.widget, 0, 2, rowno, rowno + 1,
738 Gtk::FILL, Gtk::SHRINK);
739 rowno++;
740 boolentry.signal_changed_by_user().connect(instrument_changed.make_slot());
741 }
742
743 void InstrumentProps::add_prop(LabelWidget& prop)
744 {
745 table.attach(prop.label, 0, 1, rowno, rowno + 1,
746 Gtk::FILL, Gtk::SHRINK);
747 table.attach(prop.widget, 1, 2, rowno, rowno + 1,
748 Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
749 rowno++;
750 prop.signal_changed_by_user().connect(instrument_changed.make_slot());
751 }
752
753 InstrumentProps::InstrumentProps()
754 : table(2,1),
755 quitButton(Gtk::Stock::CLOSE),
756 eName("Name"),
757 eIsDrum("Is drum"),
758 eMIDIBank("MIDI bank", 0, 16383),
759 eMIDIProgram("MIDI program"),
760 eAttenuation("Attenuation", 0, 96, 0, 1),
761 eGainPlus6("Gain +6dB", eAttenuation, -6),
762 eEffectSend("Effect send", 0, 65535),
763 eFineTune("Fine tune", -8400, 8400),
764 ePitchbendRange("Pitchbend range", 0, 12),
765 ePianoReleaseMode("Piano release mode"),
766 eDimensionKeyRangeLow("Dimension key range low"),
767 eDimensionKeyRangeHigh("Dimension key range high")
768 {
769 set_title("Instrument properties");
770
771 rowno = 0;
772 table.set_col_spacings(5);
773
774 add_prop(eName);
775 add_prop(eIsDrum);
776 add_prop(eMIDIBank);
777 add_prop(eMIDIProgram);
778 add_prop(eAttenuation);
779 add_prop(eGainPlus6);
780 add_prop(eEffectSend);
781 add_prop(eFineTune);
782 add_prop(ePitchbendRange);
783 add_prop(ePianoReleaseMode);
784 add_prop(eDimensionKeyRangeLow);
785 add_prop(eDimensionKeyRangeHigh);
786
787 eDimensionKeyRangeLow.signal_changed_by_user().connect(
788 sigc::mem_fun(*this, &InstrumentProps::key_range_low_changed));
789 eDimensionKeyRangeHigh.signal_changed_by_user().connect(
790 sigc::mem_fun(*this, &InstrumentProps::key_range_high_changed));
791
792 add(vbox);
793 table.set_border_width(5);
794 vbox.pack_start(table);
795 table.show();
796 vbox.pack_start(buttonBox, Gtk::PACK_SHRINK);
797 buttonBox.set_layout(Gtk::BUTTONBOX_END);
798 buttonBox.set_border_width(5);
799 buttonBox.show();
800 buttonBox.pack_start(quitButton);
801 quitButton.set_flags(Gtk::CAN_DEFAULT);
802 quitButton.grab_focus();
803
804 quitButton.signal_clicked().connect(
805 sigc::mem_fun(*this, &InstrumentProps::hide));
806
807 quitButton.show();
808 vbox.show();
809 show_all_children();
810 }
811
812 void InstrumentProps::set_instrument(gig::Instrument* instrument)
813 {
814 eName.set_ptr(&instrument->pInfo->Name);
815 eIsDrum.set_ptr(&instrument->IsDrum);
816 eMIDIBank.set_ptr(&instrument->MIDIBank);
817 eMIDIProgram.set_ptr(&instrument->MIDIProgram);
818 eAttenuation.set_ptr(&instrument->Attenuation);
819 eGainPlus6.set_ptr(&instrument->Attenuation);
820 eEffectSend.set_ptr(&instrument->EffectSend);
821 eFineTune.set_ptr(&instrument->FineTune);
822 ePitchbendRange.set_ptr(&instrument->PitchbendRange);
823 ePianoReleaseMode.set_ptr(&instrument->PianoReleaseMode);
824 eDimensionKeyRangeLow.set_ptr(0);
825 eDimensionKeyRangeHigh.set_ptr(0);
826 eDimensionKeyRangeLow.set_ptr(&instrument->DimensionKeyRange.low);
827 eDimensionKeyRangeHigh.set_ptr(&instrument->DimensionKeyRange.high);
828 }
829
830 void InstrumentProps::key_range_low_changed()
831 {
832 double l = eDimensionKeyRangeLow.get_value();
833 double h = eDimensionKeyRangeHigh.get_value();
834 if (h < l) eDimensionKeyRangeHigh.set_value(l);
835 }
836
837 void InstrumentProps::key_range_high_changed()
838 {
839 double l = eDimensionKeyRangeLow.get_value();
840 double h = eDimensionKeyRangeHigh.get_value();
841 if (h < l) eDimensionKeyRangeLow.set_value(h);
842 }
843
844 sigc::signal<void> InstrumentProps::signal_instrument_changed()
845 {
846 return instrument_changed;
847 }
848
849 void MainWindow::file_changed()
850 {
851 if (file && !file_is_changed) {
852 set_title("*" + get_title());
853 file_is_changed = true;
854 }
855 }
856
857 void MainWindow::load_gig(gig::File* gig, const char* filename)
858 {
859 file = 0;
860
861 this->filename = filename ? filename : _("Unsaved Gig File");
862 set_title(Glib::filename_display_basename(this->filename));
863 file_has_name = filename;
864 file_is_changed = false;
865
866 propDialog.set_info(gig->pInfo);
867
868 Gtk::MenuItem* instrument_menu =
869 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));
870
871 int instrument_index = 0;
872 Gtk::RadioMenuItem::Group instrument_group;
873 for (gig::Instrument* instrument = gig->GetFirstInstrument() ; instrument ;
874 instrument = gig->GetNextInstrument()) {
875 Gtk::TreeModel::iterator iter = m_refTreeModel->append();
876 Gtk::TreeModel::Row row = *iter;
877 row[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
878 row[m_Columns.m_col_instr] = instrument;
879 // create a menu item for this instrument
880 Gtk::RadioMenuItem* item =
881 new Gtk::RadioMenuItem(instrument_group, instrument->pInfo->Name.c_str());
882 instrument_menu->get_submenu()->append(*item);
883 item->signal_activate().connect(
884 sigc::bind(
885 sigc::mem_fun(*this, &MainWindow::on_instrument_selection_change),
886 instrument_index
887 )
888 );
889 instrument_index++;
890 }
891 instrument_menu->show();
892 instrument_menu->get_submenu()->show_all_children();
893
894 for (gig::Group* group = gig->GetFirstGroup(); group; group = gig->GetNextGroup()) {
895 if (group->Name != "") {
896 Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
897 Gtk::TreeModel::Row rowGroup = *iterGroup;
898 rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
899 rowGroup[m_SamplesModel.m_col_group] = group;
900 rowGroup[m_SamplesModel.m_col_sample] = NULL;
901 for (gig::Sample* sample = group->GetFirstSample();
902 sample; sample = group->GetNextSample()) {
903 Gtk::TreeModel::iterator iterSample =
904 m_refSamplesTreeModel->append(rowGroup.children());
905 Gtk::TreeModel::Row rowSample = *iterSample;
906 rowSample[m_SamplesModel.m_col_name] = sample->pInfo->Name.c_str();
907 rowSample[m_SamplesModel.m_col_sample] = sample;
908 rowSample[m_SamplesModel.m_col_group] = NULL;
909 }
910 }
911 }
912
913 file = gig;
914
915 // select the first instrument
916 Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
917 tree_sel_ref->select(Gtk::TreePath("0"));
918 }
919
920 void MainWindow::show_instr_props()
921 {
922 Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
923 Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
924 if (it)
925 {
926 Gtk::TreeModel::Row row = *it;
927 if (row[m_Columns.m_col_instr])
928 {
929 instrumentProps.set_instrument(row[m_Columns.m_col_instr]);
930 instrumentProps.show();
931 instrumentProps.deiconify();
932 }
933 }
934 }
935
936 void MainWindow::on_button_release(GdkEventButton* button)
937 {
938 if (button->type == GDK_2BUTTON_PRESS) {
939 show_instr_props();
940 } else if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
941 popup_menu->popup(button->button, button->time);
942 }
943 }
944
945 void MainWindow::on_instrument_selection_change(int index) {
946 m_RegionChooser.set_instrument(file->GetInstrument(index));
947 }
948
949 void MainWindow::on_sample_treeview_button_release(GdkEventButton* button) {
950 if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
951 Gtk::Menu* sample_popup =
952 dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/SamplePopupMenu"));
953 // update enabled/disabled state of sample popup items
954 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
955 Gtk::TreeModel::iterator it = sel->get_selected();
956 bool group_selected = false;
957 bool sample_selected = false;
958 if (it) {
959 Gtk::TreeModel::Row row = *it;
960 group_selected = row[m_SamplesModel.m_col_group];
961 sample_selected = row[m_SamplesModel.m_col_sample];
962 }
963 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/SampleProperties"))->
964 set_sensitive(group_selected || sample_selected);
965 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddSample"))->
966 set_sensitive(group_selected || sample_selected);
967 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddGroup"))->
968 set_sensitive(file);
969 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/RemoveSample"))->
970 set_sensitive(group_selected || sample_selected);
971 // show sample popup
972 sample_popup->popup(button->button, button->time);
973 }
974 }
975
976 void MainWindow::on_action_add_instrument() {
977 static int __instrument_indexer = 0;
978 if (!file) return;
979 gig::Instrument* instrument = file->AddInstrument();
980 __instrument_indexer++;
981 instrument->pInfo->Name =
982 "Unnamed Instrument " + ToString(__instrument_indexer);
983 // update instrument tree view
984 Gtk::TreeModel::iterator iterInstr = m_refTreeModel->append();
985 Gtk::TreeModel::Row rowInstr = *iterInstr;
986 rowInstr[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
987 rowInstr[m_Columns.m_col_instr] = instrument;
988 file_changed();
989 }
990
991 void MainWindow::on_action_remove_instrument() {
992 if (!file) return;
993 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
994 Gtk::TreeModel::iterator it = sel->get_selected();
995 if (it) {
996 Gtk::TreeModel::Row row = *it;
997 gig::Instrument* instr = row[m_Columns.m_col_instr];
998 try {
999 // remove instrument from the gig file
1000 if (instr) file->DeleteInstrument(instr);
1001 // remove respective row from instruments tree view
1002 m_refTreeModel->erase(it);
1003 file_changed();
1004 } catch (RIFF::Exception e) {
1005 Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1006 msg.run();
1007 }
1008 }
1009 }
1010
1011 void MainWindow::on_action_sample_properties() {
1012 //TODO: show a dialog where the selected sample's properties can be edited
1013 Gtk::MessageDialog msg(
1014 *this, "Sorry, yet to be implemented!", false, Gtk::MESSAGE_INFO
1015 );
1016 msg.run();
1017 }
1018
1019 void MainWindow::on_action_add_group() {
1020 static int __sample_indexer = 0;
1021 if (!file) return;
1022 gig::Group* group = file->AddGroup();
1023 group->Name = "Unnamed Group";
1024 if (__sample_indexer) group->Name += " " + ToString(__sample_indexer);
1025 __sample_indexer++;
1026 // update sample tree view
1027 Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
1028 Gtk::TreeModel::Row rowGroup = *iterGroup;
1029 rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1030 rowGroup[m_SamplesModel.m_col_sample] = NULL;
1031 rowGroup[m_SamplesModel.m_col_group] = group;
1032 file_changed();
1033 }
1034
1035 void MainWindow::on_action_add_sample() {
1036 if (!file) return;
1037 // get selected group
1038 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1039 Gtk::TreeModel::iterator it = sel->get_selected();
1040 if (!it) return;
1041 Gtk::TreeModel::Row row = *it;
1042 gig::Group* group = row[m_SamplesModel.m_col_group];
1043 if (!group) { // not a group, but a sample is selected (probably)
1044 gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1045 if (!sample) return;
1046 it = row.parent(); // resolve parent (that is the sample's group)
1047 if (!it) return;
1048 row = *it;
1049 group = row[m_SamplesModel.m_col_group];
1050 if (!group) return;
1051 }
1052 // show 'browse for file' dialog
1053 Gtk::FileChooserDialog dialog(*this, _("Add Sample(s)"));
1054 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1055 dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1056 dialog.set_select_multiple(true);
1057 Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile
1058 const char* const supportedFileTypes[] = {
1059 "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
1060 "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
1061 "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
1062 "*.W64", "*.pvf", "*.PVF", "*.xi", "*.XI", "*.htk", "*.HTK",
1063 "*.caf", "*.CAF", NULL
1064 };
1065 for (int i = 0; supportedFileTypes[i]; i++)
1066 soundfilter.add_pattern(supportedFileTypes[i]);
1067 soundfilter.set_name("Sound Files");
1068 Gtk::FileFilter allpassfilter; // matches every file
1069 allpassfilter.add_pattern("*.*");
1070 allpassfilter.set_name("All Files");
1071 dialog.add_filter(soundfilter);
1072 dialog.add_filter(allpassfilter);
1073 if (dialog.run() == Gtk::RESPONSE_OK) {
1074 Glib::ustring error_files;
1075 Glib::SListHandle<Glib::ustring> filenames = dialog.get_filenames();
1076 for (Glib::SListHandle<Glib::ustring>::iterator iter = filenames.begin();
1077 iter != filenames.end(); ++iter) {
1078 printf("Adding sample %s\n",(*iter).c_str());
1079 // use libsndfile to retrieve file informations
1080 SF_INFO info;
1081 info.format = 0;
1082 SNDFILE* hFile = sf_open((*iter).c_str(), SFM_READ, &info);
1083 try {
1084 if (!hFile) throw std::string("could not open file");
1085 int bitdepth;
1086 switch (info.format & 0xff) {
1087 case SF_FORMAT_PCM_S8:
1088 case SF_FORMAT_PCM_16:
1089 case SF_FORMAT_PCM_U8:
1090 bitdepth = 16;
1091 break;
1092 case SF_FORMAT_PCM_24:
1093 case SF_FORMAT_PCM_32:
1094 case SF_FORMAT_FLOAT:
1095 case SF_FORMAT_DOUBLE:
1096 bitdepth = 24;
1097 break;
1098 default:
1099 sf_close(hFile); // close sound file
1100 throw std::string("format not supported"); // unsupported subformat (yet?)
1101 }
1102 // add a new sample to the .gig file
1103 gig::Sample* sample = file->AddSample();
1104 // file name without path
1105 Glib::ustring filename = Glib::filename_display_basename(*iter);
1106 // remove file extension if there is one
1107 for (int i = 0; supportedFileTypes[i]; i++) {
1108 if (Glib::str_has_suffix(filename, supportedFileTypes[i] + 1)) {
1109 filename.erase(filename.length() - strlen(supportedFileTypes[i] + 1));
1110 break;
1111 }
1112 }
1113 sample->pInfo->Name = filename;
1114 sample->Channels = info.channels;
1115 sample->BitDepth = bitdepth;
1116 sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
1117 sample->SamplesPerSecond = info.samplerate;
1118 sample->AverageBytesPerSecond = sample->FrameSize * sample->SamplesPerSecond;
1119 sample->BlockAlign = sample->FrameSize;
1120 sample->SamplesTotal = info.frames;
1121
1122 SF_INSTRUMENT instrument;
1123 if (sf_command(hFile, SFC_GET_INSTRUMENT,
1124 &instrument, sizeof(instrument)) != SF_FALSE)
1125 {
1126 sample->MIDIUnityNote = instrument.basenote;
1127
1128 if (instrument.loop_count && instrument.loops[0].mode != SF_LOOP_NONE) {
1129 sample->Loops = 1;
1130
1131 switch (instrument.loops[0].mode) {
1132 case SF_LOOP_FORWARD:
1133 sample->LoopType = gig::loop_type_normal;
1134 break;
1135 case SF_LOOP_BACKWARD:
1136 sample->LoopType = gig::loop_type_backward;
1137 break;
1138 case SF_LOOP_ALTERNATING:
1139 sample->LoopType = gig::loop_type_bidirectional;
1140 break;
1141 }
1142 sample->LoopStart = instrument.loops[0].start;
1143 sample->LoopEnd = instrument.loops[0].end;
1144 sample->LoopPlayCount = instrument.loops[0].count;
1145 sample->LoopSize = sample->LoopEnd - sample->LoopStart + 1;
1146 }
1147 }
1148
1149 // schedule resizing the sample (which will be done
1150 // physically when File::Save() is called)
1151 sample->Resize(info.frames);
1152 // make sure sample is part of the selected group
1153 group->AddSample(sample);
1154 // schedule that physical resize and sample import
1155 // (data copying), performed when "Save" is requested
1156 SampleImportItem sched_item;
1157 sched_item.gig_sample = sample;
1158 sched_item.sample_path = *iter;
1159 m_SampleImportQueue.push_back(sched_item);
1160 // add sample to the tree view
1161 Gtk::TreeModel::iterator iterSample =
1162 m_refSamplesTreeModel->append(row.children());
1163 Gtk::TreeModel::Row rowSample = *iterSample;
1164 rowSample[m_SamplesModel.m_col_name] = filename;
1165 rowSample[m_SamplesModel.m_col_sample] = sample;
1166 rowSample[m_SamplesModel.m_col_group] = NULL;
1167 // close sound file
1168 sf_close(hFile);
1169 file_changed();
1170 } catch (std::string what) { // remember the files that made trouble (and their cause)
1171 if (error_files.size()) error_files += "\n";
1172 error_files += *iter += " (" + what + ")";
1173 }
1174 }
1175 // show error message box when some file(s) could not be opened / added
1176 if (error_files.size()) {
1177 Glib::ustring txt = "Could not add the following sample(s):\n" + error_files;
1178 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1179 msg.run();
1180 }
1181 }
1182 }
1183
1184 void MainWindow::on_action_remove_sample() {
1185 if (!file) return;
1186 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1187 Gtk::TreeModel::iterator it = sel->get_selected();
1188 if (it) {
1189 Gtk::TreeModel::Row row = *it;
1190 gig::Group* group = row[m_SamplesModel.m_col_group];
1191 gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1192 Glib::ustring name = row[m_SamplesModel.m_col_name];
1193 try {
1194 // remove group or sample from the gig file
1195 if (group) {
1196 // temporarily remember the samples that bolong to
1197 // that group (we need that to clean the queue)
1198 std::list<gig::Sample*> members;
1199 for (gig::Sample* pSample = group->GetFirstSample();
1200 pSample; pSample = group->GetNextSample()) {
1201 members.push_back(pSample);
1202 }
1203 // delete the group in the .gig file including the
1204 // samples that belong to the group
1205 file->DeleteGroup(group);
1206 // if sample(s) were just previously added, remove
1207 // them from the import queue
1208 for (std::list<gig::Sample*>::iterator member = members.begin();
1209 member != members.end(); ++member) {
1210 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
1211 iter != m_SampleImportQueue.end(); ++iter) {
1212 if ((*iter).gig_sample == *member) {
1213 printf("Removing previously added sample '%s' from group '%s'\n",
1214 (*iter).sample_path.c_str(), name.c_str());
1215 m_SampleImportQueue.erase(iter);
1216 break;
1217 }
1218 }
1219 }
1220 file_changed();
1221 } else if (sample) {
1222 // remove sample from the .gig file
1223 file->DeleteSample(sample);
1224 // if sample was just previously added, remove it from
1225 // the import queue
1226 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
1227 iter != m_SampleImportQueue.end(); ++iter) {
1228 if ((*iter).gig_sample == sample) {
1229 printf("Removing previously added sample '%s'\n",
1230 (*iter).sample_path.c_str());
1231 m_SampleImportQueue.erase(iter);
1232 break;
1233 }
1234 }
1235 file_changed();
1236 }
1237 // remove respective row(s) from samples tree view
1238 m_refSamplesTreeModel->erase(it);
1239 } catch (RIFF::Exception e) {
1240 Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1241 msg.run();
1242 }
1243 }
1244 }
1245
1246 void MainWindow::on_sample_treeview_drag_data_get(const Glib::RefPtr<Gdk::DragContext>&,
1247 Gtk::SelectionData& selection_data, guint, guint)
1248 {
1249 // get selected sample
1250 gig::Sample* sample = NULL;
1251 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1252 Gtk::TreeModel::iterator it = sel->get_selected();
1253 if (it) {
1254 Gtk::TreeModel::Row row = *it;
1255 sample = row[m_SamplesModel.m_col_sample];
1256 }
1257 // pass the gig::Sample as pointer
1258 selection_data.set(selection_data.get_target(), 0/*unused*/, (const guchar*)&sample,
1259 sizeof(sample)/*length of data in bytes*/);
1260 }
1261
1262 void MainWindow::on_sample_label_drop_drag_data_received(
1263 const Glib::RefPtr<Gdk::DragContext>& context, int, int,
1264 const Gtk::SelectionData& selection_data, guint, guint time)
1265 {
1266 gig::Sample* sample = *((gig::Sample**) selection_data.get_data());
1267
1268 if (sample && selection_data.get_length() == sizeof(gig::Sample*)) {
1269 if (dimreg_edit.set_sample(sample)) {
1270 std::cout << "Drop received sample \"" <<
1271 sample->pInfo->Name << "\"" << std::endl;
1272 // drop success
1273 context->drop_reply(true, time);
1274 return;
1275 }
1276 }
1277 // drop failed
1278 context->drop_reply(false, time);
1279 }
1280
1281 void MainWindow::sample_name_changed(const Gtk::TreeModel::Path& path,
1282 const Gtk::TreeModel::iterator& iter) {
1283 if (!iter) return;
1284 Gtk::TreeModel::Row row = *iter;
1285 Glib::ustring name = row[m_SamplesModel.m_col_name];
1286 gig::Group* group = row[m_SamplesModel.m_col_group];
1287 gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1288 if (group) {
1289 if (group->Name != name) {
1290 group->Name = name;
1291 printf("group name changed\n");
1292 file_changed();
1293 }
1294 } else if (sample) {
1295 if (sample->pInfo->Name != name.raw()) {
1296 sample->pInfo->Name = name.raw();
1297 printf("sample name changed\n");
1298 file_changed();
1299 }
1300 }
1301 }
1302
1303 void MainWindow::instrument_name_changed(const Gtk::TreeModel::Path& path,
1304 const Gtk::TreeModel::iterator& iter) {
1305 if (!iter) return;
1306 Gtk::TreeModel::Row row = *iter;
1307 Glib::ustring name = row[m_Columns.m_col_name];
1308 gig::Instrument* instrument = row[m_Columns.m_col_instr];
1309 if (instrument && instrument->pInfo->Name != name.raw()) {
1310 instrument->pInfo->Name = name.raw();
1311 file_changed();
1312 }
1313 }

  ViewVC Help
Powered by ViewVC