1 2 /* 3 * The Real SoundTracker - module info page 4 * 5 * Copyright (C) 1998-2019 Michael Krause 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 20 */ 21 22 #include <gdk/gdkkeysyms.h> 23 #include <glib.h> 24 #include <glib/gi18n.h> 25 #include <glib/gprintf.h> 26 #include <math.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 31 #include "extspinbutton.h" 32 #include "gui-subs.h" 33 #include "gui.h" 34 #include "history.h" 35 #include "instrument-editor.h" 36 #include "keys.h" 37 #include "main.h" 38 #include "module-info.h" 39 #include "sample-editor.h" 40 #include "st-subs.h" 41 #include "track-editor.h" 42 #include "xm.h" 43 44 static GtkWidget *ilist, *slist, *ilist2, *slist2, *songname, *sw1, *sw2; 45 static GtkWidget *freqmode_w[2], *ptmode_toggle; 46 static GtkWidget *ins1_label, *smp1_label, *ins2_label, *smp2_label, *mix_label1, *mix_label2; 47 static guint curi = 0, curs = 0, desti = 0, dests = 0, mix_prev_note; 48 static gfloat mixlevel = 50.0; 49 static gboolean is_tuning = FALSE; 50 51 struct tuner { 52 GtkWidget *frame, *note_label, *note2_label, *note_spin; 53 GtkWidget *period_label, *period_label2, *period_spin, *play, *stop; 54 guint note, mode, period; 55 gboolean is_ref; 56 gint timer; 57 const gchar *label_text; 58 }; 59 60 static struct tuner *tuning, *ref; 61 62 static STSample prev_sample = {{0}}; 63 static guint32 prev_alloc_length = 0; 64 65 static const gchar* mode1[] = {N_("Single"), N_("Cyclic"), N_("Keyboard")}; 66 static const gchar* mode2[] = {N_("Single"), N_("Cyclic"), N_("Coupled")}; 67 enum { 68 MODE_SINGLE = 0, 69 MODE_CYCLIC, 70 MODE_KEYBOARD, 71 MODE_COUPLED = MODE_KEYBOARD, 72 MODE_LAST 73 }; 74 75 static void 76 ptmode_changed(GtkToggleButton* widget) 77 { 78 if (xm) { 79 history_log_toggle_button(widget, _("Protracker mode changing"), 80 HISTORY_FLAG_LOG_PAGE, xm->flags & XM_FLAGS_IS_MOD); 81 if (gtk_toggle_button_get_active(widget)) 82 xm->flags |= XM_FLAGS_IS_MOD; 83 else 84 xm->flags &= ~XM_FLAGS_IS_MOD; 85 } 86 } 87 88 static void 89 freqmode_changed(GtkToggleButton* widget) 90 { 91 if (xm && gtk_toggle_button_get_active(widget)) { 92 gint m = find_current_toggle(freqmode_w, 2); 93 94 history_log_radio_group(freqmode_w, _("Frequency mode changing"), 95 HISTORY_FLAG_LOG_PAGE, (xm->flags & XM_FLAGS_AMIGA_FREQ) != 0 ? 1 : 0, 2); 96 if (m) 97 xm->flags |= XM_FLAGS_AMIGA_FREQ; 98 else 99 xm->flags &= ~XM_FLAGS_AMIGA_FREQ; 100 } 101 } 102 103 static void 104 songname_changed(GtkEntry* entry) 105 { 106 gchar* term; 107 108 history_log_entry(entry, _("Song name changing"), 20 * 4, 109 HISTORY_FLAG_LOG_PAGE, xm->utf_name); 110 g_utf8_strncpy(xm->utf_name, gtk_entry_get_text(entry), 20); 111 term = g_utf8_offset_to_pointer(xm->utf_name, 21); 112 term[0] = 0; 113 xm->needs_conversion = TRUE; 114 } 115 116 static void 117 modinfo_update_all_samples(const gint n, const gboolean second) 118 { 119 guint i; 120 GtkTreeModel* model; 121 GtkWidget* list = second ? slist2 : slist; 122 GtkListStore* slist_store = GUI_GET_LIST_STORE(list); 123 124 model = gui_list_freeze(list); 125 for (i = 0; i < ST_NUM_SAMPLES(&xm->instruments[n]); i++) { 126 GtkTreeIter iter; 127 128 if (!gui_list_get_iter(i, slist_store, &iter)) 129 return; /* Some bullshit happens :-/ */ 130 gtk_list_store_set(slist_store, &iter, 1, 131 xm->instruments[n].samples[i].utf_name, -1); 132 } 133 gui_list_thaw(list, model); 134 } 135 136 static void 137 modinfo_update_instrument_full(const gint n, const gboolean second) 138 { 139 GtkTreeIter iter; 140 GtkListStore* list_store = GUI_GET_LIST_STORE(second ? ilist2 : ilist); 141 142 if (!gui_list_get_iter(n, list_store, &iter)) 143 return; /* Some bullshit happens :-/ */ 144 gtk_list_store_set(list_store, &iter, 1, xm->instruments[n].utf_name, 145 2, st_instrument_num_samples(&xm->instruments[n]), -1); 146 147 if (n == (second ? desti : curi)) 148 modinfo_update_all_samples(n, second); 149 } 150 151 static void 152 update_labels(struct tuner* t, 153 GtkWidget *label, 154 GtkWidget *mix_label, 155 const gint n, 156 const gint ins, 157 const gint smp) 158 { 159 gchar *buf; 160 161 buf = g_strdup_printf("%i", n); 162 gtk_label_set_text(GTK_LABEL(label), buf); 163 g_free(buf); 164 buf = g_strdup_printf(_("%sIns. %i, Smp. %i"), t->label_text, ins + 1, smp); 165 gtk_frame_set_label(GTK_FRAME(t->frame), buf); 166 g_free(buf); 167 buf = g_strdup_printf(_("I%i, S%i"), ins + 1, smp); 168 gtk_label_set_text(GTK_LABEL(mix_label), buf); 169 g_free(buf); 170 } 171 172 static void 173 ilist_select(GtkTreeSelection* sel) 174 { 175 gint row = gui_list_get_selection_index(sel); 176 177 if (row != -1 && row != curi) { 178 curi = row; 179 gui_set_current_instrument(row + 1); 180 update_labels(tuning, ins1_label, mix_label1, row + 1, curi, curs); 181 } 182 } 183 184 static void 185 slist_select(GtkTreeSelection* sel) 186 { 187 gint row = gui_list_get_selection_index(sel); 188 189 if (row != -1 && row != curs) { 190 curs = row; 191 gui_set_current_sample(row); 192 update_labels(tuning, smp1_label, mix_label1, row, curi, curs); 193 } 194 } 195 196 static void 197 ilist2_select(GtkTreeSelection* sel) 198 { 199 gint row = gui_list_get_selection_index(sel); 200 201 if (row != -1 && row != desti) { 202 desti = row; 203 modinfo_update_all_samples(row, TRUE); 204 update_labels(ref, ins2_label, mix_label2, row + 1, desti, dests); 205 } 206 } 207 208 static void 209 slist2_select(GtkTreeSelection* sel) 210 { 211 gint row = gui_list_get_selection_index(sel); 212 213 if (row != -1 && row != dests) { 214 dests = row; 215 update_labels(ref, smp2_label, mix_label2, row, desti, dests); 216 } 217 } 218 219 static GtkWidget* 220 add_label(const gchar* title, 221 const gchar* value, 222 const GtkWidget* box) 223 { 224 GtkWidget *box2, *thing, *frame; 225 226 box2 = gtk_hbox_new(FALSE, 4); 227 gtk_box_pack_start(GTK_BOX(box), box2, FALSE, FALSE, 0); 228 229 thing = gtk_label_new(_(title)); 230 gtk_box_pack_start(GTK_BOX(box2), thing, FALSE, FALSE, 0); 231 232 frame = gtk_frame_new(NULL); 233 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); 234 gtk_box_pack_end(GTK_BOX(box2), frame, FALSE, FALSE, 0); 235 gtk_widget_show(frame); 236 237 thing = gtk_label_new(value); 238 gtk_misc_set_alignment(GTK_MISC(thing), 1.0, 0.5); 239 gtk_container_add(GTK_CONTAINER(frame), thing); 240 241 return thing; 242 } 243 244 static void 245 exp_change(GtkExpander *expndr) 246 { 247 is_tuning = gtk_expander_get_expanded(expndr); 248 249 (is_tuning ? gtk_widget_show : gtk_widget_hide)(sw1); 250 (is_tuning ? gtk_widget_show : gtk_widget_hide)(sw2); 251 if (!is_tuning) { 252 modinfo_stop_cycling(); 253 gui_play_stop(); 254 } 255 } 256 257 static void 258 modinfo_xcopy_ins(const gpointer data) 259 { 260 if (curi != desti) { 261 gint action = GPOINTER_TO_INT(data); 262 STInstrument* src_ins = &xm->instruments[curi]; 263 STInstrument* dst_ins = &xm->instruments[desti]; 264 265 /* It's simplier just to stop playing instead of performing some doubtful locks */ 266 gui_play_stop(); 267 268 instrument_editor_xcopy_instruments(src_ins, dst_ins, action); 269 if (action) { 270 instrument_editor_update(FALSE); 271 sample_editor_update(); 272 modinfo_update_instrument(curi); 273 } 274 modinfo_update_instrument(desti); 275 } 276 } 277 278 static 279 void modinfo_update_sample_full(const gint ins, const gint smp, const gboolean second) 280 { 281 GtkTreeIter iter; 282 GtkListStore* list_store = GUI_GET_LIST_STORE(second ? slist2 : slist); 283 284 if (!gui_list_get_iter(smp, list_store, &iter)) 285 return; /* Some bullshit happens :-/ */ 286 gtk_list_store_set(list_store, &iter, 1, 287 xm->instruments[ins].samples[smp].utf_name, -1); 288 } 289 290 /* Not a simple case. We have to back up both a sample and the 291 sample map of an instrument using one argument */ 292 struct Smp_n_MapBackup { 293 gint ins, smp; /* Destination instrument and sample */ 294 gint8 samplemap[96]; 295 STSample sample; 296 gint16 data[1]; 297 }; 298 299 static struct Smp_n_MapBackup* 300 make_sample_copy_arg(const gint ins, const gint smp, const guint32 backup_size) 301 { 302 struct Smp_n_MapBackup* arg; 303 STInstrument* src_ins = &xm->instruments[ins]; 304 STSample* src_smp = &src_ins->samples[smp]; 305 306 arg = g_malloc(backup_size); 307 if (!arg) { 308 gui_oom_error(); 309 return NULL; 310 } 311 312 arg->ins = ins; 313 arg->smp = smp; 314 memcpy(arg->samplemap, src_ins->samplemap, sizeof(arg->samplemap)); 315 arg->sample = *src_smp; 316 if (src_smp->sample.length) 317 memcpy(arg->data, src_smp->sample.data, src_smp->sample.length * sizeof(arg->data[0])); 318 319 return arg; 320 } 321 322 static void sample_copy_undo(const gint ins, const gint smp, const gboolean redo, 323 gpointer arg, gpointer data) 324 { 325 struct Smp_n_MapBackup* bup = arg; 326 STInstrument* dst_ins = &xm->instruments[bup->ins]; 327 STSample* dst_smp = &dst_ins->samples[bup->smp]; 328 gint8* tmp_smap = alloca(sizeof(bup->samplemap)); 329 const gsize data_length = dst_smp->sample.length * sizeof(dst_smp->sample.data[0]); 330 gint16* tmp_data = NULL; 331 STSample tmp_smp; 332 GMutex tmp_lock; 333 334 if (data_length) { 335 tmp_data = g_malloc(data_length); 336 if (!tmp_data) { 337 gui_oom_error(); 338 return; 339 } 340 memcpy(tmp_data, dst_smp->sample.data, data_length); 341 } 342 tmp_smp = *dst_smp; 343 memcpy(tmp_smap, dst_ins->samplemap, sizeof(dst_ins->samplemap)); 344 345 g_mutex_lock(&dst_smp->sample.lock); 346 tmp_lock = dst_smp->sample.lock; 347 if (dst_smp->sample.length && dst_smp->sample.data) 348 g_free(dst_smp->sample.data); 349 memcpy(dst_ins->samplemap, bup->samplemap, sizeof(dst_ins->samplemap)); 350 *dst_smp = bup->sample; 351 if (dst_smp->sample.length) { 352 dst_smp->sample.data = g_new(gint16, dst_smp->sample.length); 353 memcpy(dst_smp->sample.data, bup->data, dst_smp->sample.length * sizeof(bup->data[0])); 354 } else 355 dst_smp->sample.data = NULL; 356 dst_smp->sample.lock = tmp_lock; 357 g_mutex_unlock(&dst_smp->sample.lock); 358 359 bup->sample = tmp_smp; 360 if (tmp_data) { 361 memcpy(bup->data, tmp_data, bup->sample.sample.length * sizeof(tmp_data[0])); 362 g_free(tmp_data); 363 } 364 memcpy(bup->samplemap, tmp_smap, sizeof(bup->samplemap)); 365 366 modinfo_update_instrument(bup->ins); 367 } 368 369 static void 370 sample_xchg_undo(const gint ins, const gint smp, const gboolean redo, 371 gpointer arg, gpointer data) 372 { 373 sample_editor_xcopy_samples(arg, data, TRUE); 374 modinfo_update_instrument_full(ins - 1, FALSE); 375 modinfo_update_instrument_full(desti, TRUE); 376 } 377 378 static void 379 modinfo_xcopy_smp(const gpointer data) 380 { 381 if (curi != desti || curs != dests) { 382 gint action = GPOINTER_TO_INT(data); 383 STInstrument* dest_ins = &xm->instruments[desti]; 384 STInstrument* src_ins = &xm->instruments[curi]; 385 STSample* dest_smp = &dest_ins->samples[dests]; 386 STSample* src_smp = &src_ins->samples[curs]; 387 388 if (action) { 389 history_log_action(HISTORY_ACTION_POINTER_NOFREE, _("Sample exchanging"), 390 HISTORY_FLAG_LOG_ALL, sample_xchg_undo, src_smp, 0, dest_smp); 391 } else { 392 struct Smp_n_MapBackup* arg; 393 const guint32 data_length = MAX(src_smp->sample.length, dest_smp->sample.length); 394 const guint32 backup_size = sizeof(struct Smp_n_MapBackup) + 395 sizeof(arg->data[0]) * (data_length - 1); 396 397 if (history_check_size(backup_size)) { 398 arg = make_sample_copy_arg(desti, dests, backup_size); 399 history_log_action(HISTORY_ACTION_POINTER, _("Sample overwriting"), 400 HISTORY_FLAG_LOG_ALL, sample_copy_undo, NULL, backup_size, arg); 401 } else if (!history_query_oversized(mainwindow)) 402 return; 403 } 404 405 if (st_instrument_num_samples(dest_ins) == 0) { 406 st_clean_instrument_full(dest_ins, NULL, FALSE); 407 memset(dest_ins->samplemap, dests, sizeof(dest_ins->samplemap)); 408 } 409 if (action && st_instrument_num_samples(src_ins) == 0) { 410 st_clean_instrument_full(src_ins, NULL, FALSE); 411 memset(src_ins->samplemap, curs, sizeof(src_ins->samplemap)); 412 } 413 sample_editor_xcopy_samples(src_smp, dest_smp, action); 414 415 if (action) { 416 sample_editor_update(); 417 instrument_editor_update(TRUE); 418 } 419 modinfo_update_instrument(desti); 420 if (curi == desti) 421 modinfo_update_sample_full(desti, dests, FALSE); 422 } 423 } 424 425 static void 426 put_labelled_spin_button(const gchar* title, GtkAdjustment* adj, GtkWidget* box) 427 { 428 GtkWidget *hbox, *thing; 429 430 hbox = gtk_hbox_new(FALSE, 4); 431 gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0); 432 thing = gtk_label_new(title); 433 gtk_box_pack_start(GTK_BOX(hbox), thing, FALSE, FALSE, 0); 434 thing = extspinbutton_new(adj, 0, 0, TRUE); 435 gtk_box_pack_end(GTK_BOX(hbox), thing, FALSE, FALSE, 0); 436 } 437 438 static void 439 note_changed(GtkSpinButton* spin, struct tuner* t) 440 { 441 t->note = gtk_spin_button_get_value_as_int(spin); 442 gtk_label_set_text(GTK_LABEL(t->note_label), tracker_get_note_name(t->note)); 443 } 444 445 static void 446 mix_prev_note_changed(GtkSpinButton* spin, GtkLabel* label) 447 { 448 mix_prev_note = gtk_spin_button_get_value_as_int(spin); 449 gtk_label_set_text(label, tracker_get_note_name(mix_prev_note)); 450 } 451 452 static void 453 period_changed(GtkSpinButton* spin, struct tuner* t) 454 { 455 t->period = lrint(gtk_spin_button_get_value(spin) * 1000.0); 456 } 457 458 static void 459 mode_changed(GtkComboBox* combo, struct tuner* t) 460 { 461 gboolean active; 462 463 t->mode = gtk_combo_box_get_active(combo); 464 465 active = (t->mode == MODE_CYCLIC); 466 gtk_widget_set_sensitive(t->period_label, active); 467 gtk_widget_set_sensitive(t->period_spin, active); 468 gtk_widget_set_sensitive(t->period_label2, active); 469 470 active = !(t->mode == MODE_KEYBOARD); /* == MODE_COUPLED also */ 471 gtk_widget_set_sensitive(t->play, active); 472 gtk_widget_set_sensitive(t->stop, active); 473 if (!t->is_ref) { 474 gtk_widget_set_sensitive(t->note2_label, active); 475 gtk_widget_set_sensitive(t->note_spin, active); 476 } 477 } 478 479 static gboolean 480 play_note(gpointer data) 481 { 482 struct tuner* t = (struct tuner*)data; 483 484 gint ins_num = t->is_ref ? desti : curi; 485 gint smp_num = t->is_ref ? dests : curs; 486 STSample* sample = &xm->instruments[ins_num].samples[smp_num]; 487 488 if (!sample) { 489 t->timer = -1; 490 return FALSE; 491 } 492 493 gui_play_note_full(t->is_ref ? 0 : 1, t->note + 1, sample, 0, sample->sample.length, TRUE); 494 if (!t->is_ref && ref->mode == MODE_COUPLED) { 495 sample = &xm->instruments[desti].samples[dests]; 496 if (sample) 497 gui_play_note_full(0, ref->note + 1, sample, 0, sample->sample.length, FALSE); 498 } 499 500 return TRUE; 501 } 502 503 static void 504 play_clicked(struct tuner* t) 505 { 506 switch (t->mode) { 507 case MODE_SINGLE: 508 play_note(t); 509 break; 510 case MODE_CYCLIC: 511 if (t->timer == -1) { 512 play_note(t); 513 t->timer = g_timeout_add(t->period, play_note, t); 514 } 515 break; 516 default: 517 break; 518 } 519 } 520 521 static void 522 stop_clicked(struct tuner* t) 523 { 524 if (t->timer != -1) { 525 g_source_remove(t->timer); 526 t->timer = -1; 527 } 528 gui_stop_note(t->is_ref ? 0 : 1); 529 if (!t->is_ref && ref->mode == MODE_COUPLED) 530 gui_stop_note(0); 531 } 532 533 static struct tuner* 534 tuner_new(const gboolean is_ref, const gchar* label_text) 535 { 536 struct tuner* t = g_new(struct tuner, 1); 537 538 t->note = 48; 539 t->mode = 0; 540 t->period = 1000; 541 t->is_ref = is_ref; 542 t->timer = -1; 543 t->label_text = label_text; 544 545 t->frame = gtk_frame_new(""); 546 gtk_frame_set_shadow_type(GTK_FRAME(t->frame), GTK_SHADOW_IN); 547 548 return t; 549 } 550 551 static GtkWidget* 552 tuner_populate(struct tuner* t) 553 { 554 GtkWidget *vbox, *hbox, *thing; 555 GtkListStore* list_store; 556 GtkTreeIter iter; 557 gint i, width, height; 558 559 vbox = gtk_vbox_new(TRUE, 2); 560 hbox = gtk_hbox_new(FALSE, 4); 561 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); 562 563 t->play = thing = gtk_button_new(); 564 gtk_container_add(GTK_CONTAINER(thing), gui_get_pixmap(GUI_PIXMAP_PLAY)); 565 gtk_box_pack_start(GTK_BOX(hbox), thing, FALSE, FALSE, 0); 566 g_signal_connect_swapped(thing, "clicked", G_CALLBACK(play_clicked), t); 567 568 t->stop = thing = gtk_button_new(); 569 gtk_container_add(GTK_CONTAINER(thing), gui_get_pixmap(GUI_PIXMAP_STOP)); 570 gtk_box_pack_start(GTK_BOX(hbox), thing, FALSE, FALSE, 0); 571 g_signal_connect_swapped(thing, "clicked", G_CALLBACK(stop_clicked), t); 572 573 t->period_label = thing = gtk_label_new(_("Period")); 574 gtk_box_pack_start(GTK_BOX(hbox), thing, FALSE, FALSE, 0); 575 gtk_widget_set_sensitive(thing, FALSE); 576 t->period_label2 = thing = gtk_label_new(_("s")); 577 gtk_box_pack_end(GTK_BOX(hbox), thing, FALSE, FALSE, 0); 578 gtk_widget_set_sensitive(thing, FALSE); 579 t->period_spin = thing = extspinbutton_new( 580 GTK_ADJUSTMENT(gtk_adjustment_new(1.0, 0.0, 10.0, 0.1, 1.0, 0.0)), 581 0.0, 1, TRUE); 582 gtk_box_pack_end(GTK_BOX(hbox), thing, FALSE, FALSE, 0); 583 gtk_widget_set_sensitive(thing, FALSE); 584 g_signal_connect(thing, "value-changed", G_CALLBACK(period_changed), t); 585 586 hbox = gtk_hbox_new(FALSE, 4); 587 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); 588 thing = gtk_hbox_new(FALSE, 4); 589 gtk_box_pack_start(GTK_BOX(hbox), thing, FALSE, FALSE, 0); 590 591 thing = gtk_label_new(_("Mode")); 592 gtk_box_pack_start(GTK_BOX(hbox), thing, FALSE, FALSE, 0); 593 594 list_store = gtk_list_store_new(1, G_TYPE_STRING); 595 for (i = 0; i < MODE_LAST; i++) { 596 gtk_list_store_append(list_store, &iter); 597 gtk_list_store_set(list_store, &iter, 0, _((t->is_ref ? mode2 : mode1)[i]), -1); 598 } 599 thing = gui_combo_new(list_store); 600 gtk_combo_box_set_active(GTK_COMBO_BOX(thing), 0); 601 gtk_box_pack_end(GTK_BOX(hbox), thing, FALSE, FALSE, 0); 602 g_signal_connect(thing, "changed", G_CALLBACK(mode_changed), t); 603 604 hbox = gtk_hbox_new(FALSE, 4); 605 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); 606 thing = gtk_hbox_new(FALSE, 4); 607 gtk_box_pack_start(GTK_BOX(hbox), thing, FALSE, FALSE, 0); 608 609 t->note2_label = thing = gtk_label_new(_("Note")); 610 gtk_box_pack_start(GTK_BOX(hbox), thing, FALSE, FALSE, 0); 611 612 thing = gtk_frame_new(NULL); 613 gtk_frame_set_shadow_type(GTK_FRAME(thing), GTK_SHADOW_IN); 614 gtk_box_pack_end(GTK_BOX(hbox), thing, FALSE, FALSE, 0); 615 t->note_label = gtk_label_new(""); 616 gui_get_pixel_size(t->note_label, " C#4 ", &width, &height); 617 gtk_widget_set_size_request(t->note_label, width, -1); 618 gtk_container_add(GTK_CONTAINER(thing), t->note_label); 619 620 t->note_spin = thing = extspinbutton_new( 621 GTK_ADJUSTMENT(gtk_adjustment_new(48.0, 0.0, NUM_NOTES - 1, 1.0, 5.0, 0.0)), 622 0.0, 0, TRUE); 623 gtk_box_pack_end(GTK_BOX(hbox), thing, FALSE, FALSE, 0); 624 g_signal_connect(thing, "value-changed", G_CALLBACK(note_changed), t); 625 note_changed(GTK_SPIN_BUTTON(thing), t); 626 627 return vbox; 628 } 629 630 static void 631 mixlevel_changed(GtkAdjustment* adj) 632 { 633 mixlevel = gtk_adjustment_get_value(adj); 634 } 635 636 static void 637 same_sample_warning(void) 638 { 639 static GtkWidget* dialog = NULL; 640 641 gui_warning_dialog(&dialog, _("Mixing a sample with itself is not a useful idea..."), FALSE); 642 } 643 644 static void 645 mix_samples(const STSample* dst, 646 STSample* sample, 647 STSample* sample1, 648 const guint32 length1, 649 const guint32 length2, 650 gfloat mlevel) 651 { 652 guint32 i; 653 STSample *rest; 654 655 for (i = 0; i < MIN(length1, length2); i++) 656 dst->sample.data[i] = lrintf((float)sample->sample.data[i] * mlevel / 100.0 + 657 (float)sample1->sample.data[i] * (100.0 - mlevel) / 100.0); 658 659 if (length1 < length2) { 660 mlevel = 100.0 - mlevel; 661 rest = sample1; 662 } else 663 rest = sample; 664 665 for (; i < MAX(length1, length2); i++) 666 dst->sample.data[i] = lrintf((float)rest->sample.data[i] * mlevel / 100.0); 667 } 668 669 static void 670 mix_clicked(void) 671 { 672 STSample* sample = &xm->instruments[curi].samples[curs]; 673 STSample* sample1 = &xm->instruments[desti].samples[dests]; 674 guint32 length1 = sample->sample.length, length2 = sample1->sample.length; 675 676 /* Silently ignore empty samples */ 677 if ((!sample->sample.data) || (!sample1->sample.data)) 678 return; 679 if ((!length1) || (!length2)) 680 return; 681 682 if (curi == desti && curs == dests) { 683 same_sample_warning(); 684 return; 685 } 686 687 if (!sample_editor_check_and_log_sample(sample, N_("Mixing samples"), 688 HISTORY_FLAG_LOG_INS | HISTORY_FLAG_LOG_SMP | 689 HISTORY_SET_PAGE(NOTEBOOK_PAGE_SAMPLE_EDITOR), 690 MAX(length1, length2))) 691 return; 692 693 g_mutex_lock(&sample->sample.lock); 694 if (length1 < length2) { 695 sample->sample.data = realloc(sample->sample.data, length2 * sizeof(sample->sample.data[0])); 696 sample->sample.length = length2; 697 } 698 mix_samples(sample, sample, sample1, length1, length2, mixlevel); 699 700 g_mutex_unlock(&sample->sample.lock); 701 sample_editor_update(); 702 } 703 704 static void 705 mixer_preview(void) 706 { 707 STSample* sample = &xm->instruments[curi].samples[curs]; 708 STSample* sample1 = &xm->instruments[desti].samples[dests]; 709 guint32 length1 = sample->sample.length, length2 = sample1->sample.length, length; 710 gpointer sampledata; 711 712 /* Silently ignore empty samples */ 713 if ((!sample->sample.data) || (!sample1->sample.data)) 714 return; 715 if ((!length1) || (!length2)) 716 return; 717 718 if (curi == desti && curs == dests) { 719 same_sample_warning(); 720 return; 721 } 722 723 length = MAX(length1, length2); 724 /* Indeed, we need to update the sample data only if either a mixlevel or one of the samples 725 is changed (instrument/sample number or the sample data itself. But tracking the sample 726 data modifications (by editing, loading new samples / instrumens / module) is rather 727 complicated. So we update te sample data all the time though... */ 728 if (!prev_sample.sample.data) { 729 prev_sample.sample.data = malloc(length * sizeof(sample->sample.data[0])); 730 prev_alloc_length = length; 731 } else if (prev_alloc_length < length) { 732 g_free(prev_sample.sample.data); 733 prev_sample.sample.data = malloc(length * sizeof(sample->sample.data[0])); 734 prev_alloc_length = length; 735 } 736 737 sampledata = prev_sample.sample.data; 738 memcpy(&prev_sample, sample, sizeof(prev_sample)); 739 prev_sample.sample.data = sampledata; 740 mix_samples(&prev_sample, sample, sample1, length1, length2, mixlevel); 741 prev_sample.sample.length = length; 742 743 gui_play_stop(); 744 gui_play_note_full(0, mix_prev_note + 1, &prev_sample, 0, prev_sample.sample.length, FALSE); 745 } 746 747 void modinfo_page_create(GtkNotebook* nb) 748 { 749 GtkWidget *hbox, *thing, *vbox, *expndr, *hbox2, *vbox2, *hbox3, *alignment, *frame, *prev_note_spin; 750 GtkAdjustment *adj; 751 GtkListStore* list_store; 752 GtkTreeIter iter; 753 GtkTreeModel* model; 754 const gchar* ititles[3] = { "n", N_("Instrument Name"), N_("#smpl") }; 755 const gchar* stitles[2] = { "n", N_("Sample Name") }; 756 GType itypes[3] = { G_TYPE_INT, G_TYPE_STRING, G_TYPE_INT }; 757 GType stypes[2] = { G_TYPE_INT, G_TYPE_STRING }; 758 const gfloat ialignments[3] = { 0.5, 0.0, 0.5 }; 759 const gfloat salignments[2] = { 0.5, 0.0 }; 760 const gboolean iexpands[3] = { FALSE, TRUE, FALSE }; 761 const gboolean sexpands[3] = { FALSE, TRUE }; 762 const gchar* freqlabels[] = { N_("Linear"), N_("Amiga") }; 763 gint i, width, height; 764 765 vbox = gtk_vbox_new(FALSE, 4); 766 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10); 767 gtk_notebook_append_page(nb, vbox, gtk_label_new(_("Module Info"))); 768 gtk_widget_show(vbox); 769 770 hbox = gtk_hbox_new(TRUE, 10); 771 gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); 772 gtk_widget_show(hbox); 773 774 /* Main instruments and samples lists */ 775 ilist = gui_list_in_scrolled_window_full(3, ititles, hbox, itypes, ialignments, 776 iexpands, GTK_SELECTION_BROWSE, TRUE, TRUE, &thing, 777 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 778 gtk_widget_show_all(thing); 779 list_store = GUI_GET_LIST_STORE(ilist); 780 model = gui_list_freeze(ilist); 781 for (i = 1; i <= ST_NUM_INSTRUMENTS(xm); i++) { 782 gtk_list_store_append(list_store, &iter); 783 gtk_list_store_set(list_store, &iter, 0, i, 1, "", 2, 0, -1); 784 } 785 gui_list_thaw(ilist, model); 786 gui_list_handle_selection(ilist, G_CALLBACK(ilist_select), NULL); 787 788 slist = gui_list_in_scrolled_window_full(2, stitles, hbox, stypes, salignments, 789 sexpands, GTK_SELECTION_BROWSE, TRUE, TRUE, &thing, 790 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 791 gtk_widget_show_all(thing); 792 list_store = GUI_GET_LIST_STORE(slist); 793 model = gui_list_freeze(slist); 794 for (i = 0; i < ST_NUM_SAMPLES(&xm->instruments[0]); i++) { 795 gtk_list_store_append(list_store, &iter); 796 gtk_list_store_set(list_store, &iter, 0, i, 1, "", -1); 797 } 798 gui_list_thaw(slist, model); 799 gui_list_handle_selection(slist, G_CALLBACK(slist_select), NULL); 800 801 /* Secondary instruments and samples lists for extended functions */ 802 ilist2 = gui_list_in_scrolled_window_full(3, ititles, hbox, itypes, ialignments, 803 iexpands, GTK_SELECTION_BROWSE, TRUE, TRUE, &sw1, 804 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 805 gtk_widget_show(ilist2); 806 list_store = GUI_GET_LIST_STORE(ilist2); 807 model = gui_list_freeze(ilist2); 808 for (i = 1; i <= ST_NUM_INSTRUMENTS(xm); i++) { 809 gtk_list_store_append(list_store, &iter); 810 gtk_list_store_set(list_store, &iter, 0, i, 1, "", 2, 0, -1); 811 } 812 gui_list_thaw(ilist2, model); 813 gui_list_handle_selection(ilist2, G_CALLBACK(ilist2_select), NULL); 814 815 slist2 = gui_list_in_scrolled_window_full(2, stitles, hbox, stypes, salignments, 816 sexpands, GTK_SELECTION_BROWSE, TRUE, TRUE, &sw2, 817 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 818 gtk_widget_show(slist2); 819 list_store = GUI_GET_LIST_STORE(slist2); 820 model = gui_list_freeze(slist2); 821 for (i = 0; i < ST_NUM_SAMPLES(&xm->instruments[0]); i++) { 822 gtk_list_store_append(list_store, &iter); 823 gtk_list_store_set(list_store, &iter, 0, i, 1, "", -1); 824 } 825 gui_list_thaw(slist2, model); 826 gui_list_handle_selection(slist2, G_CALLBACK(slist2_select), NULL); 827 828 /* Module metadata */ 829 hbox = gtk_hbox_new(FALSE, 4); 830 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); 831 832 thing = gtk_label_new(_("Songname:")); 833 gtk_box_pack_start(GTK_BOX(hbox), thing, FALSE, TRUE, 0); 834 835 gui_get_text_entry(20, songname_changed, &songname); 836 gtk_box_pack_start(GTK_BOX(hbox), songname, TRUE, TRUE, 0); 837 838 add_empty_hbox(hbox); 839 thing = make_labelled_radio_group_box(_("Frequencies:"), freqlabels, freqmode_w, freqmode_changed); 840 gtk_box_pack_start(GTK_BOX(hbox), thing, FALSE, TRUE, 0); 841 add_empty_hbox(hbox); 842 843 ptmode_toggle = gtk_check_button_new_with_label(_("ProTracker Mode")); 844 gtk_box_pack_start(GTK_BOX(hbox), ptmode_toggle, FALSE, TRUE, 0); 845 gtk_widget_show(ptmode_toggle); 846 g_signal_connect(ptmode_toggle, "toggled", 847 G_CALLBACK(ptmode_changed), NULL); 848 849 add_empty_hbox(hbox); 850 gtk_widget_show_all(hbox); 851 852 thing = gtk_hseparator_new(); 853 gtk_box_pack_start(GTK_BOX(vbox), thing, FALSE, FALSE, 0); 854 gtk_widget_show(thing); 855 856 /* Extended editor */ 857 expndr = gtk_expander_new(_("Extended Instrument/Sample Editor")); 858 gtk_expander_set_expanded(GTK_EXPANDER(expndr), FALSE); 859 gtk_box_pack_end(GTK_BOX(vbox), expndr, FALSE, FALSE, 0); 860 g_signal_connect(expndr, "notify::expanded", G_CALLBACK(exp_change), NULL); 861 hbox = gtk_hbox_new(FALSE, 4); 862 gtk_container_add(GTK_CONTAINER(expndr), hbox); 863 864 vbox = gtk_vbox_new(TRUE, 2); 865 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); 866 ins1_label = add_label(N_("Ins. 1"), "1", vbox); 867 gui_get_pixel_size(ins1_label, "000", &width, &height); 868 gtk_widget_set_size_request(ins1_label, width, -1); 869 smp1_label = add_label(N_("Smp. 1"), "0", vbox); 870 gtk_widget_set_size_request(smp1_label, width, -1); 871 ins2_label = add_label(N_("Ins. 2"), "1", vbox); 872 gtk_widget_set_size_request(ins2_label, width, -1); 873 smp2_label = add_label(N_("Smp. 2"), "0", vbox); 874 gtk_widget_set_size_request(smp2_label, width, -1); 875 876 thing = gtk_vseparator_new(); 877 gtk_box_pack_start(GTK_BOX(hbox), thing, FALSE, FALSE, 0); 878 879 vbox = gtk_vbox_new(TRUE, 2); 880 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); 881 882 thing = gtk_button_new_with_label(_("I1 => I2")); 883 gtk_widget_set_tooltip_text(thing, _("Copy Instrument 1 to Instrument 2")); 884 gtk_box_pack_start(GTK_BOX(vbox), thing, FALSE, FALSE, 0); 885 g_signal_connect_swapped(thing, "clicked", G_CALLBACK(modinfo_xcopy_ins), GINT_TO_POINTER(0)); 886 887 thing = gtk_button_new_with_label(_("I1 <=> I2")); 888 gtk_widget_set_tooltip_text(thing, _("Exchange Instruments 1 and 2")); 889 gtk_box_pack_start(GTK_BOX(vbox), thing, FALSE, FALSE, 0); 890 g_signal_connect_swapped(thing, "clicked", G_CALLBACK(modinfo_xcopy_ins), GINT_TO_POINTER(1)); 891 892 thing = gtk_button_new_with_label(_("S1 => S2")); 893 gtk_widget_set_tooltip_text(thing, _("Copy Sample 1 to Sample 2")); 894 gtk_box_pack_start(GTK_BOX(vbox), thing, FALSE, FALSE, 0); 895 g_signal_connect_swapped(thing, "clicked", G_CALLBACK(modinfo_xcopy_smp), GINT_TO_POINTER(0)); 896 897 thing = gtk_button_new_with_label(_("S1 <=> S2")); 898 gtk_widget_set_tooltip_text(thing, _("Exchange Samples 1 and 2")); 899 gtk_box_pack_start(GTK_BOX(vbox), thing, FALSE, FALSE, 0); 900 g_signal_connect_swapped(thing, "clicked", G_CALLBACK(modinfo_xcopy_smp), GINT_TO_POINTER(1)); 901 902 thing = gtk_vseparator_new(); 903 gtk_box_pack_start(GTK_BOX(hbox), thing, FALSE, FALSE, 0); 904 905 /* Mixer */ 906 907 vbox = gtk_vbox_new(FALSE, 2); 908 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); 909 thing = gtk_label_new(_("Mixing balance")); 910 gtk_misc_set_alignment(GTK_MISC(thing), 0.5, 0.5); 911 gtk_box_pack_start(GTK_BOX(vbox), thing, FALSE, TRUE, 0); 912 913 hbox2 = gtk_hbox_new(FALSE, 2); 914 gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, TRUE, 0); 915 vbox2 = gtk_vbox_new(FALSE, 2); 916 gtk_box_pack_start(GTK_BOX(hbox2), vbox2, TRUE, TRUE, 0); 917 hbox3 = gtk_hbox_new(FALSE, 0); 918 gtk_box_pack_start(GTK_BOX(vbox2), hbox3, FALSE, TRUE, 0); 919 920 mix_label1 = gtk_label_new(_("I1, S0")); 921 gtk_box_pack_start(GTK_BOX(hbox3), mix_label1, FALSE, TRUE, 0); 922 923 mix_label2 = gtk_label_new(_("I1, S0")); 924 gtk_box_pack_end(GTK_BOX(hbox3), mix_label2, FALSE, TRUE, 0); 925 926 adj = GTK_ADJUSTMENT(gtk_adjustment_new(50.0, 0.0, 100.0, 1.0, 10.0, 0.0)); 927 thing = gtk_hscale_new(adj); 928 gtk_scale_set_draw_value(GTK_SCALE(thing), FALSE); 929 gtk_box_pack_start(GTK_BOX(vbox2), thing, FALSE, TRUE, 0); 930 g_signal_connect(adj, "value-changed", G_CALLBACK(mixlevel_changed), NULL); 931 932 alignment = gtk_alignment_new(0.5, 1.0, 0.0, 0.0); 933 gtk_box_pack_start(GTK_BOX(hbox2), alignment, FALSE, FALSE, 0); 934 hbox3 = gtk_hbox_new(FALSE, 2); 935 gtk_container_add(GTK_CONTAINER(alignment), hbox3); 936 937 thing = extspinbutton_new(adj, 0.0, 0, TRUE); 938 gtk_box_pack_start(GTK_BOX(hbox3), thing, FALSE, FALSE, 0); 939 thing = gtk_label_new("%"); 940 gtk_box_pack_start(GTK_BOX(hbox3), thing, FALSE, FALSE, 0); 941 942 hbox2 = gtk_hbox_new(FALSE, 4); 943 gtk_box_pack_end(GTK_BOX(vbox), hbox2, FALSE, TRUE, 0); 944 945 thing = gtk_label_new(_("Note")); 946 gtk_widget_set_tooltip_text(thing, _("Note to demonstrate result")); 947 gtk_box_pack_start(GTK_BOX(hbox2), thing, FALSE, FALSE, 0); 948 949 prev_note_spin = extspinbutton_new( 950 GTK_ADJUSTMENT(gtk_adjustment_new(48.0, 0.0, NUM_NOTES - 1, 1.0, 5.0, 0.0)), 951 0.0, 0, TRUE); 952 gtk_box_pack_start(GTK_BOX(hbox2), prev_note_spin, FALSE, FALSE, 0); 953 954 frame = gtk_frame_new(NULL); 955 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); 956 gtk_box_pack_start(GTK_BOX(hbox2), frame, FALSE, FALSE, 0); 957 thing = gtk_label_new(""); 958 gui_get_pixel_size(thing, " C#4 ", &width, &height); 959 gtk_widget_set_size_request(thing, width, -1); 960 gtk_container_add(GTK_CONTAINER(frame), thing); 961 g_signal_connect(prev_note_spin, "value-changed", G_CALLBACK(mix_prev_note_changed), thing); 962 mix_prev_note_changed(GTK_SPIN_BUTTON(prev_note_spin), GTK_LABEL(thing)); 963 964 thing = gtk_button_new_with_label(_("Demo")); 965 gtk_widget_set_tooltip_text(thing, _("Play the mixed sample without module modification")); 966 gtk_box_pack_start(GTK_BOX(hbox2), thing, TRUE, TRUE, 0); 967 g_signal_connect(thing, "clicked", G_CALLBACK(mixer_preview), NULL); 968 969 thing = gtk_button_new_with_label(_("Mix!")); 970 gtk_widget_set_tooltip_text(thing, 971 _("Mix sample 1 of instrument 1 with sample 2 of instrument 2 with the given balance ratio")); 972 gtk_box_pack_start(GTK_BOX(hbox2), thing, TRUE, TRUE, 0); 973 g_signal_connect(thing, "clicked", G_CALLBACK(mix_clicked), NULL); 974 975 thing = gtk_vseparator_new(); 976 gtk_box_pack_start(GTK_BOX(hbox), thing, FALSE, FALSE, 0); 977 978 /* Tuning facility, tuning sample */ 979 tuning = tuner_new(FALSE, _("Tuning: ")); 980 gtk_box_pack_start(GTK_BOX(hbox), tuning->frame, FALSE, FALSE, 0); 981 update_labels(tuning, ins1_label, mix_label1, 1, 0, 0); 982 983 hbox2 = gtk_hbox_new(FALSE, 4); 984 gtk_container_set_border_width(GTK_CONTAINER(hbox2), 4); 985 gtk_container_add(GTK_CONTAINER(tuning->frame), hbox2); 986 vbox = gtk_vbox_new(TRUE, 2); 987 gtk_box_pack_start(GTK_BOX(hbox2), vbox, FALSE, FALSE, 0); 988 989 thing = gtk_hscale_new(sample_editor_get_adjustment(SAMPLE_EDITOR_FINETUNE)); 990 gtk_scale_set_draw_value(GTK_SCALE(thing), FALSE); 991 gtk_box_pack_start(GTK_BOX(vbox), thing, FALSE, FALSE, 0); 992 put_labelled_spin_button(_("Finetune"), sample_editor_get_adjustment(SAMPLE_EDITOR_FINETUNE), vbox); 993 put_labelled_spin_button(_("RelNote"), sample_editor_get_adjustment(SAMPLE_EDITOR_RELNOTE), vbox); 994 995 vbox = tuner_populate(tuning); 996 gtk_box_pack_start(GTK_BOX(hbox2), vbox, FALSE, FALSE, 0); 997 998 /* Reference sample */ 999 ref = tuner_new(TRUE, _("Reference: ")); 1000 gtk_box_pack_start(GTK_BOX(hbox), ref->frame, FALSE, FALSE, 0); 1001 1002 vbox = tuner_populate(ref); 1003 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); 1004 gtk_container_add(GTK_CONTAINER(ref->frame), vbox); 1005 update_labels(ref, ins2_label, mix_label2, 1, 0, 0); 1006 1007 gtk_widget_show_all(expndr); 1008 } 1009 1010 gboolean 1011 modinfo_page_handle_keys(int shift, 1012 int ctrl, 1013 int alt, 1014 guint32 keyval, 1015 gboolean pressed) 1016 { 1017 gint modifiers = ENCODE_MODIFIERS(shift, ctrl, alt); 1018 gint i = keys_get_key_meaning(keyval, modifiers, -1); 1019 gboolean handled = FALSE, samples_focused; 1020 1021 if (i != -1 && KEYS_MEANING_TYPE(i) == KEYS_MEANING_NOTE) { 1022 if (tuning->mode == MODE_KEYBOARD && is_tuning) { 1023 STSample* sample = &xm->instruments[curi].samples[curs]; 1024 1025 handled = gui_play_note_no_repeat(keyval, modifiers, pressed, 1026 sample, 0, sample->sample.length, 1, FALSE, NULL, TRUE); 1027 1028 /* handled means that it's a real, not fake, keypress and the note is correct */ 1029 if (ref->mode == MODE_COUPLED && handled) { 1030 if (pressed) { 1031 sample = &xm->instruments[desti].samples[dests]; 1032 if (sample) 1033 gui_play_note_full(0, ref->note + 1, sample, 0, sample->sample.length, FALSE); 1034 } else 1035 gui_stop_note(0); 1036 } 1037 } else 1038 track_editor_do_the_note_key(i, pressed, keyval, ENCODE_MODIFIERS(shift, ctrl, alt), TRUE); 1039 return TRUE; 1040 } 1041 1042 if (!pressed) 1043 return FALSE; 1044 1045 samples_focused = (GTK_WINDOW(mainwindow)->focus_widget == slist); 1046 switch (keyval) { 1047 case GDK_Tab: 1048 case GDK_ISO_Left_Tab: 1049 gtk_window_set_focus(GTK_WINDOW(mainwindow), samples_focused ? ilist : slist); 1050 handled = TRUE; 1051 break; 1052 case GDK_Up: 1053 if (samples_focused) 1054 gui_offset_current_sample(shift ? -4 : -1); 1055 else 1056 gui_offset_current_instrument(shift ? -5 : -1); 1057 handled = TRUE; 1058 break; 1059 case GDK_Down: 1060 if (samples_focused) 1061 gui_offset_current_sample(shift ? 4 : 1); 1062 else 1063 gui_offset_current_instrument(shift ? 5 : 1); 1064 handled = TRUE; 1065 break; 1066 case GDK_Delete: 1067 handled = instrument_editor_clear_current_instrument(); 1068 break; 1069 default: 1070 break; 1071 } 1072 return handled; 1073 } 1074 1075 void modinfo_stop_cycling(void) 1076 { 1077 if (tuning->timer != -1) { 1078 g_source_remove(tuning->timer); 1079 tuning->timer = -1; 1080 } 1081 if (ref->timer != -1) { 1082 g_source_remove(ref->timer); 1083 ref->timer = -1; 1084 } 1085 } 1086 1087 void 1088 modinfo_update_instrument(int n) 1089 { 1090 modinfo_update_instrument_full(n, FALSE); 1091 modinfo_update_instrument_full(n, TRUE); 1092 } 1093 1094 void modinfo_update_sample(int n) 1095 { 1096 modinfo_update_sample_full(curi, n, FALSE); 1097 modinfo_update_sample_full(curi, n, TRUE); 1098 } 1099 1100 void modinfo_update_all(void) 1101 { 1102 gint i; 1103 const gint freq_index = (xm->flags & XM_FLAGS_AMIGA_FREQ) != 0 ? 1 : 0; 1104 1105 for (i = 0; i < ST_NUM_INSTRUMENTS(xm); i++) 1106 modinfo_update_instrument(i); 1107 1108 gtk_entry_set_text(GTK_ENTRY(songname), xm->utf_name); 1109 1110 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ptmode_toggle), xm->flags & XM_FLAGS_IS_MOD); 1111 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(freqmode_w[freq_index]), TRUE); 1112 } 1113 1114 void modinfo_set_current_instrument(int n) 1115 { 1116 g_return_if_fail(n >= 0 && n < ST_NUM_INSTRUMENTS(xm)); 1117 1118 gui_list_select(ilist, n, FALSE, 0.0); 1119 modinfo_update_all_samples(n, FALSE); 1120 } 1121 1122 void modinfo_set_current_sample(int n) 1123 { 1124 g_return_if_fail(n >= 0 && n < ST_NUM_SAMPLES(&xm->instruments[0])); 1125 1126 gui_list_select(slist, n, FALSE, 0.0); 1127 } 1128 1129 gint modinfo_get_current_sample(void) 1130 { 1131 return curs; 1132 } 1133