1 /** \file sidsoundwidget.c
2 * \brief Settings for SID emulation
3 *
4 * \author Bas Wassink <b.wassink@ziggo.nl>
5 */
6
7 /* Note: These only make sense with a SidCart attached for certain machines
8 *
9 * $VICERES SidEngine all
10 * $VICERES SidStereo all
11 * $VICERES SidResidSampling all
12 * $VICERES SidResidPassband all
13 * $VICERES SidResidGain all
14 * $VICERES SidResidFilterBias all
15 * $VICERES SidResid8580Passband all
16 * $VICERES SidResid8580Gain all
17 * $VICERES SidResid8580FilterBias all
18 * $VICERES SidFilters all
19 * $VICERES Sid2AddressStart all
20 * $VICERES Sid3AddressStart all
21 * $VICERES Sid4AddressStart -vsid
22 * $VICERES Sid5AddressStart -vsid
23 * $VICERES Sid6AddressStart -vsid
24 * $VICERES Sid7AddressStart -vsid
25 * $VICERES Sid8AddressStart -vsid
26 * (Until PSID files support a fourth SID, this will be -vsid)
27 */
28
29 /*
30 * This file is part of VICE, the Versatile Commodore Emulator.
31 * See README for copyright notice.
32 *
33 * This program is free software; you can redistribute it and/or modify
34 * it under the terms of the GNU General Public License as published by
35 * the Free Software Foundation; either version 2 of the License, or
36 * (at your option) any later version.
37 *
38 * This program is distributed in the hope that it will be useful,
39 * but WITHOUT ANY WARRANTY; without even the implied warranty of
40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41 * GNU General Public License for more details.
42 *
43 * You should have received a copy of the GNU General Public License
44 * along with this program; if not, write to the Free Software
45 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
46 * 02111-1307 USA.
47 */
48
49
50 #include "vice.h"
51
52 #include <assert.h>
53 #include <gtk/gtk.h>
54 #include <stdbool.h>
55
56 #include "vice_gtk3.h"
57 #include "lib.h"
58 #include "machine.h"
59 #include "resources.h"
60 #include "sid.h"
61
62
63 #ifdef HAVE_CATWEASELMKIII
64 # include "catweaselmkiii.h"
65 #endif
66
67 #ifdef HAVE_HARDSID
68 # include "hardsid.h"
69 #endif
70
71 #ifdef HAVE_PARSID
72 # include "parsid.h"
73 #endif
74
75 #include "sidenginemodelwidget.h"
76 #include "mixerwidget.h"
77
78 #include "sidsoundwidget.h"
79
80
81
82 #ifdef HAVE_RESID
83 /** \brief Values for the "SidResidSampling" resource
84 */
85 static const vice_gtk3_radiogroup_entry_t resid_sampling_modes[] = {
86 { "Fast", 0 },
87 { "Interpolation", 1 },
88 { "Resampling", 2 },
89 { "Fast resampling", 3 },
90 { NULL, -1 }
91 };
92 #endif
93
94
95 /** \brief I/O addresses for extra SID's for the C64
96 *
97 * \note Yes, I know I can generate this table
98 */
99 static const vice_gtk3_combo_entry_int_t sid_address_c64[] = {
100 { "$d420", 0xd420 }, { "$d440", 0xd440 }, { "$d460", 0xd460 },
101 { "$d480", 0xd480 }, { "$d4a0", 0xd4a0 }, { "$d4c0", 0xd4c0 },
102 { "$d4e0", 0xd4e0 },
103
104 { "$d500", 0xd500 }, { "$d520", 0xd520 }, { "$d540", 0xd540 },
105 { "$d560", 0xd560 }, { "$d580", 0xd580 }, { "$d5a0", 0xd5a0 },
106 { "$d5c0", 0xd5c0 }, { "$d5e0", 0xd5e0 },
107
108 { "$d600", 0xd600 }, { "$d620", 0xd620 }, { "$d640", 0xd640 },
109 { "$d660", 0xd660 }, { "$d680", 0xd680 }, { "$d6a0", 0xd6a0 },
110 { "$d6c0", 0xd6c0 }, { "$d6e0", 0xd6e0 },
111
112 { "$d700", 0xd700 }, { "$d720", 0xd720 }, { "$d740", 0xd740 },
113 { "$d760", 0xd760 }, { "$d780", 0xd780 }, { "$d7a0", 0xd7a0 },
114 { "$d7c0", 0xd7c0 }, { "$d7e0", 0xd7e0 },
115
116 { "$de00", 0xde00 }, { "$de20", 0xde20 }, { "$de40", 0xde40 },
117 { "$de60", 0xde60 }, { "$de80", 0xde80 }, { "$dea0", 0xdea0 },
118 { "$dec0", 0xdec0 }, { "$dee0", 0xdee0 },
119
120 { "$df00", 0xdf00 }, { "$df20", 0xdf20 }, { "$df40", 0xdf40 },
121 { "$df60", 0xdf60 }, { "$df80", 0xdf80 }, { "$dfa0", 0xdfa0 },
122 { "$dfc0", 0xdfc0 }, { "$dfe0", 0xdfe0 },
123 VICE_GTK3_COMBO_ENTRY_INT_LIST_END
124 };
125
126
127 /** \brief I/O addresses for extra SID's for the C128
128 */
129 static const vice_gtk3_combo_entry_int_t sid_address_c128[] = {
130 { "$d420", 0xd420 }, { "$d440", 0xd440 }, { "$d460", 0xd460 },
131 { "$d480", 0xd480 }, { "$d4a0", 0xd4a0 }, { "$d4c0", 0xd4c0 },
132 { "$d4e0", 0xd4e0 },
133
134 { "$d700", 0xd700 }, { "$d720", 0xd720 }, { "$d740", 0xd740 },
135 { "$d760", 0xd760 }, { "$d780", 0xd780 }, { "$d7a0", 0xd7a0 },
136 { "$d7c0", 0xd7c0 }, { "$d7e0", 0xd7e0 },
137
138 { "$de00", 0xde00 }, { "$de20", 0xde20 }, { "$de40", 0xde40 },
139 { "$de60", 0xde60 }, { "$de80", 0xde80 }, { "$dea0", 0xdea0 },
140 { "$dec0", 0xdec0 }, { "$dee0", 0xdee0 },
141
142 { "$df00", 0xdf00 }, { "$df20", 0xdf20 }, { "$df40", 0xdf40 },
143 { "$df60", 0xdf60 }, { "$df80", 0xdf80 }, { "$dfa0", 0xdfa0 },
144 { "$dfc0", 0xdfc0 }, { "$dfe0", 0xdfe0 },
145 VICE_GTK3_COMBO_ENTRY_INT_LIST_END
146 };
147
148
149 #ifdef HAVE_RESID
150 /** \brief Reference to resid sampling widget
151 *
152 * Used to enable/disable when the SID engine changes
153 */
154 static GtkWidget *resid_sampling;
155
156 /** \brief Reference to the SidResidPassband widget
157 *
158 * Used to enable/disable the widget based on the SidFilters setting
159 */
160 static GtkWidget *resid_6581_passband;
161
162 /** \brief Reference to the SidResidGain widget
163 *
164 * Used to enable/disable the widget based on the SidFilters setting
165 */
166 static GtkWidget *resid_6581_gain;
167
168 /** \brief Reference to the SidResidFilterBias widget
169 *
170 * Used to enable/disable the widget based on the SidFilters setting
171 */
172 static GtkWidget *resid_6581_bias;
173
174 /** \brief Reference to the SidResidPassband widget
175 *
176 * Used to enable/disable the widget based on the SidFilters setting
177 */
178 static GtkWidget *resid_8580_passband;
179
180 /** \brief Reference to the SidResidGain widget
181 *
182 * Used to enable/disable the widget based on the SidFilters setting
183 */
184 static GtkWidget *resid_8580_gain;
185
186 /** \brief Reference to the SidResidFilterBias widget
187 *
188 * Used to enable/disable the widget based on the SidFilters setting
189 */
190 static GtkWidget *resid_8580_bias;
191 #endif
192
193 /** \brief Reference to the extra SID address widgets
194 *
195 * Used to enable/disable depending on the number of SIDs active
196 */
197 static GtkWidget *address_widgets[SOUND_SIDS_MAX];
198
199
200 /** \brief Reference to the SID filters checkbox
201 */
202 GtkWidget *filters;
203
204 #ifdef HAVE_RESID
205 static GtkWidget *resid_6581_passband_button;
206 static GtkWidget *resid_6581_gain_button;
207 static GtkWidget *resid_6581_bias_button;
208 static GtkWidget *resid_8580_passband_button;
209 static GtkWidget *resid_8580_gain_button;
210 static GtkWidget *resid_8580_bias_button;
211
212 static GtkWidget *resid_6581_grid;
213 static GtkWidget *resid_8580_grid;
214
215
216 static GtkWidget *resid_6581_passband_spin;
217 static GtkWidget *resid_6581_gain_spin;
218 static GtkWidget *resid_6581_bias_spin;
219
220 #endif
221
222
223 static GtkWidget *num_sids_widget;
224
225
226 /** \brief Extra callback registered to the 'number of SIDs' radiogroup
227 *
228 * XXX: This function is also used in the constructor of the main widget to
229 * set the initial sensitivity of the address widgets, with NULL passed
230 * as the widget. I should probably refactor that code to have a separate
231 * function to set sensitivity to avoid this hack.
232 *
233 * \param[in] widget widget triggering the event
234 * \param[in] count number of extra SIDs (0 - SOUND_SID_MAX-1)
235 */
on_sid_count_changed(GtkWidget * widget,gpointer data)236 static void on_sid_count_changed(GtkWidget *widget, gpointer data)
237 {
238 int count;
239
240 if (widget == NULL) {
241 /* called from main widget constructor: count is in `data` */
242 count = GPOINTER_TO_INT(data);
243 } else {
244 /* called from an event, use the spin button's value */
245 count = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
246 }
247 debug_gtk3("extra SIDs count changed to %d.", count);
248
249 if (sid_machine_can_have_multiple_sids()) {
250 gtk_widget_set_sensitive(address_widgets[0], count > 0);
251 gtk_widget_set_sensitive(address_widgets[1], count > 1);
252 if (machine_class != VICE_MACHINE_VSID) {
253 gtk_widget_set_sensitive(address_widgets[2], count > 2);
254 gtk_widget_set_sensitive(address_widgets[3], count > 3);
255 gtk_widget_set_sensitive(address_widgets[4], count > 4);
256 gtk_widget_set_sensitive(address_widgets[5], count > 5);
257 gtk_widget_set_sensitive(address_widgets[6], count > 6);
258 }
259 }
260 }
261
262
263 #ifdef HAVE_RESID
264 /** \brief Handler for "clicked" event of reset-to-default for passband
265 *
266 * Restores the ReSID passband slider back to default
267 *
268 * \param[in] widget button
269 * \param[in] user_data extra data for event (unused)
270 */
on_resid_6581_passband_default_clicked(GtkWidget * widget,gpointer user_data)271 static void on_resid_6581_passband_default_clicked(GtkWidget *widget,
272 gpointer user_data)
273 {
274 vice_gtk3_resource_scale_int_reset(resid_6581_passband);
275 }
276
277
278 /** \brief Handler for "clicked" event of reset-to-default for gain
279 *
280 * Restores the ReSID gain slider back to default
281 *
282 * \param[in] widget button
283 * \param[in] user_data extra data for event (unused)
284 */
on_resid_6581_gain_default_clicked(GtkWidget * widget,gpointer user_data)285 static void on_resid_6581_gain_default_clicked(GtkWidget *widget,
286 gpointer user_data)
287 {
288 vice_gtk3_resource_scale_int_reset(resid_6581_gain);
289 }
290
291
292 /** \brief Handler for "clicked" event of reset-to-default for filter bias
293 *
294 * Restores the ReSID filter bias slider back to default
295 *
296 * \param[in] widget button
297 * \param[in] user_data extra data for event (unused)
298 */
on_resid_6581_bias_default_clicked(GtkWidget * widget,gpointer user_data)299 static void on_resid_6581_bias_default_clicked(GtkWidget *widget,
300 gpointer user_data)
301 {
302 vice_gtk3_resource_scale_int_reset(resid_6581_bias);
303
304 }
305
306 /** \brief Handler for "clicked" event of reset-to-default for 8580 passband
307 *
308 * Restores the 8580 ReSID passband slider back to default
309 *
310 * \param[in] widget button
311 * \param[in] user_data extra data for event (unused)
312 */
on_resid_8580_passband_default_clicked(GtkWidget * widget,gpointer user_data)313 static void on_resid_8580_passband_default_clicked(GtkWidget *widget,
314 gpointer user_data)
315 {
316 vice_gtk3_resource_scale_int_reset(resid_8580_passband);
317 }
318
319
320 /** \brief Handler for "clicked" event of reset-to-default for 8580 gain
321 *
322 * Restores the 8580 ReSID gain slider back to default
323 *
324 * \param[in] widget button
325 * \param[in] user_data extra data for event (unused)
326 */
on_resid_8580_gain_default_clicked(GtkWidget * widget,gpointer user_data)327 static void on_resid_8580_gain_default_clicked(GtkWidget *widget,
328 gpointer user_data)
329 {
330 vice_gtk3_resource_scale_int_reset(resid_8580_gain);
331 }
332
333
334 /** \brief Handler for "clicked" event of reset-to-default for 8580 filter bias
335 *
336 * Restores the 8580 ReSID filter bias slider back to default
337 *
338 * \param[in] widget button
339 * \param[in] user_data extra data for event (unused)
340 */
on_resid_8580_bias_default_clicked(GtkWidget * widget,gpointer user_data)341 static void on_resid_8580_bias_default_clicked(GtkWidget *widget,
342 gpointer user_data)
343 {
344 vice_gtk3_resource_scale_int_reset(resid_8580_bias);
345
346 }
347 #endif
348
349 #ifdef HAVE_RESID
on_spin_value_changed(GtkWidget * spin,gpointer data)350 static void on_spin_value_changed(GtkWidget *spin, gpointer data)
351 {
352 debug_gtk3("Callled.");
353 vice_gtk3_resource_scale_int_sync(data);
354 }
355 #endif
356
357
358 #ifdef HAVE_RESID
359 /** \brief Create spinbutton controlling \a resource and updating \a slider
360 *
361 * \param[in] resource resource name
362 * \param[in] low spinbox lowest value
363 * \param[in] high spinbox highest value
364 * \param[in] step spinbox step
365 * \param[in,out] slider slider widget controlling \a resource
366 *
367 * \return GtkSpinBox
368 */
create_spin(const char * resource,int low,int high,int step,GtkWidget * slider)369 static GtkWidget *create_spin(
370 const char *resource,
371 int low, int high, int step,
372 GtkWidget *slider)
373 {
374 GtkWidget *spin;
375
376 spin = vice_gtk3_resource_spin_int_new(resource, low, high, step);
377 g_signal_connect(spin, "value-changed", G_CALLBACK(on_spin_value_changed),
378 slider);
379 /* add a bit of spacing (TODO: mabye use CSS?) */
380 g_object_set(G_OBJECT(spin), "margin-left", 16 , NULL);
381 return spin;
382 }
383 #endif
384
385
386 /** \brief Extra callback for the SID engine/model widget
387 *
388 * \param[in] engine SID engine ID
389 * \param[in] model SID model ID
390 */
engine_model_changed_callback(int engine,int model)391 static void engine_model_changed_callback(int engine, int model)
392 {
393 #ifdef HAVE_RESID
394 gboolean is_resid = engine == SID_ENGINE_RESID;
395 #endif
396 debug_gtk3("engine: %d, model = %d.", engine, model);
397
398 /* Show proper ReSID slider widgets
399 *
400 * We can't check old model vs new model here, since the resource
401 * SidModel has already been updated.
402 */
403 #ifdef HAVE_RESID
404 if (model == 1 || model == 2) {
405 gtk_widget_show(resid_8580_grid);
406 gtk_widget_hide(resid_6581_grid);
407 } else {
408 gtk_widget_show(resid_6581_grid);
409 gtk_widget_hide(resid_8580_grid);
410 }
411
412 /*
413 * Update mixer widget in the statusbar
414 */
415 mixer_widget_sid_type_changed();
416 #endif
417
418 #ifdef HAVE_RESID
419 gtk_widget_set_sensitive(filters, is_resid);
420 gtk_widget_set_sensitive(resid_6581_grid, is_resid);
421 gtk_widget_set_sensitive(resid_8580_grid, is_resid);
422 gtk_widget_set_sensitive(resid_sampling, is_resid);
423 #endif
424 }
425
426
427 #ifdef HAVE_RESID
428 /** \brief Create widget to control ReSID sampling method
429 *
430 * \return GtkGrid
431 */
create_resid_sampling_widget(void)432 static GtkWidget *create_resid_sampling_widget(void)
433 {
434 GtkWidget *grid;
435 GtkWidget *label;
436 GtkWidget *radio_group;
437
438 grid = gtk_grid_new();
439 g_object_set(grid, "margin-left", 8, NULL);
440
441 label = gtk_label_new(NULL);
442 gtk_label_set_markup(GTK_LABEL(label), "<b>ReSID sampling method</b>");
443 gtk_widget_set_halign(label, GTK_ALIGN_START);
444 g_object_set(label, "margin-bottom", 8, NULL);
445 gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1);
446
447 radio_group = vice_gtk3_resource_radiogroup_new("SidResidSampling",
448 resid_sampling_modes, GTK_ORIENTATION_VERTICAL);
449 g_object_set(radio_group, "margin-left", 16, NULL);
450 gtk_grid_attach(GTK_GRID(grid), radio_group, 0, 1, 1, 1);
451
452 gtk_widget_show_all(grid);
453 return grid;
454 }
455 #endif
456
457
458 /** \brief Create widget to set the number of emulated SID's
459 *
460 * \return GtkGrid
461 */
create_num_sids_widget(void)462 static GtkWidget *create_num_sids_widget(void)
463 {
464 GtkWidget *grid;
465 GtkWidget *spin;
466 int max_sids;
467
468 grid = vice_gtk3_grid_new_spaced_with_label(16, 8, "Extra SIDs", 2);
469
470 if (machine_class == VICE_MACHINE_VSID) {
471 /* FIXME: perhaps rename to SOUNDS_SIDS_MAX_[P|V]SID? */
472 max_sids = SID_COUNT_MAX_PSID;
473 } else {
474 max_sids = SOUND_SIDS_MAX;
475 }
476
477 /* create spinbutton for the 'SidStereo' resource */
478 spin = vice_gtk3_resource_spin_int_new("SidStereo", 0, max_sids - 1, 1);
479 g_object_set(G_OBJECT(spin), "margin-left", 16, NULL);
480 gtk_widget_set_halign(spin, GTK_ALIGN_START);
481 gtk_widget_set_hexpand(spin, FALSE);
482 g_signal_connect(spin, "value-changed", G_CALLBACK(on_sid_count_changed),
483 NULL);
484 gtk_grid_attach(GTK_GRID(grid), spin, 0, 1, 1, 1);
485 gtk_widget_show_all(grid);
486
487 num_sids_widget = spin;
488 return grid;
489 }
490
491
492 /** \brief Create widget for extra SID addresses
493 *
494 * \param[in] sid extra SID number (1-7)
495 *
496 * \return GtkGrid
497 */
create_extra_sid_address_widget(int sid)498 static GtkWidget *create_extra_sid_address_widget(int sid)
499 {
500 GtkWidget *widget;
501 const vice_gtk3_combo_entry_int_t *entries;
502 char label[256];
503 char *resource_name;
504
505 resource_name = lib_msprintf("Sid%dAddressStart", sid + 1);
506
507 g_snprintf(label, 256, "SID #%d", sid + 1);
508 entries = machine_class == VICE_MACHINE_C128
509 ? sid_address_c128 : sid_address_c64;
510
511 widget = vice_gtk3_resource_combo_box_int_new_with_label(resource_name,
512 entries,
513 label);
514 gtk_widget_show_all(widget);
515
516 lib_free(resource_name);
517
518 return widget;
519 }
520
521
522 #ifdef HAVE_RESID
523
on_resid_6581_passband_change(GtkWidget * widget,gpointer data)524 static void on_resid_6581_passband_change(GtkWidget *widget, gpointer data)
525 {
526 double value = gtk_range_get_value(GTK_RANGE(widget));
527 gtk_spin_button_set_value(GTK_SPIN_BUTTON(resid_6581_passband_spin), value);
528 }
529
530
on_resid_6581_gain_change(GtkWidget * widget,gpointer data)531 static void on_resid_6581_gain_change(GtkWidget *widget, gpointer data)
532 {
533 double value = gtk_range_get_value(GTK_RANGE(widget));
534 gtk_spin_button_set_value(GTK_SPIN_BUTTON(resid_6581_gain_spin), value);
535 }
536
537
on_resid_6581_bias_change(GtkWidget * widget,gpointer data)538 static void on_resid_6581_bias_change(GtkWidget *widget, gpointer data)
539 {
540 double value = gtk_range_get_value(GTK_RANGE(widget));
541 gtk_spin_button_set_value(GTK_SPIN_BUTTON(resid_6581_bias_spin), value);
542 }
543
544
on_resid_6581_passband_spin_change(GtkWidget * widget,gpointer data)545 static void on_resid_6581_passband_spin_change(GtkWidget *widget, gpointer data)
546 {
547 debug_gtk3("Callled!");
548 double value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget));
549 debug_gtk3("Setting to %lf", value);
550 gtk_range_set_value(GTK_RANGE(resid_6581_passband), value);
551 }
552
553
on_resid_6581_gain_spin_change(GtkWidget * widget,gpointer data)554 static void on_resid_6581_gain_spin_change(GtkWidget *widget, gpointer data)
555 {
556 debug_gtk3("Callled!");
557 double value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget));
558 debug_gtk3("Setting to %lf", value);
559 gtk_range_set_value(GTK_RANGE(resid_6581_gain), value);
560 }
561
562
on_resid_6581_bias_spin_change(GtkWidget * widget,gpointer data)563 static void on_resid_6581_bias_spin_change(GtkWidget *widget, gpointer data)
564 {
565 debug_gtk3("Callled!");
566 double value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget));
567 debug_gtk3("Setting to %lf", value);
568 gtk_range_set_value(GTK_RANGE(resid_6581_bias), value);
569 }
570 #endif
571
572
573
574 #ifdef HAVE_RESID
575 /** \brief Create scale to control the "SidResidPassband" resource
576 *
577 * \return GtkScale
578 */
create_resid_6581_passband_widget(void)579 static GtkWidget *create_resid_6581_passband_widget(void)
580 {
581 GtkWidget *scale;
582
583 scale = vice_gtk3_resource_scale_int_new("SidResidPassband",
584 GTK_ORIENTATION_HORIZONTAL, 0, 90, 5);
585
586 g_signal_connect(scale, "value-changed",
587 G_CALLBACK(on_resid_6581_passband_change),
588 NULL);
589 return scale;
590 }
591
592
create_resid_6581_passband_spin(GtkWidget * slider)593 static GtkWidget *create_resid_6581_passband_spin(GtkWidget *slider)
594 {
595 GtkWidget *spin;
596 spin = create_spin("SidReSidPassBand", 0, 90,1, slider);
597
598 g_signal_connect(
599 spin,
600 "value-changed",
601 G_CALLBACK(on_resid_6581_passband_spin_change),
602 NULL);
603 return spin;
604 }
605
606
create_resid_6581_gain_spin(GtkWidget * slider)607 static GtkWidget *create_resid_6581_gain_spin(GtkWidget *slider)
608 {
609 GtkWidget *spin;
610 spin = create_spin("SidReSidGain", 90, 100, 1, slider);
611
612 g_signal_connect(
613 spin,
614 "value-changed",
615 G_CALLBACK(on_resid_6581_gain_spin_change),
616 NULL);
617 return spin;
618 }
619
620
create_resid_6581_bias_spin(GtkWidget * slider)621 static GtkWidget *create_resid_6581_bias_spin(GtkWidget *slider)
622 {
623 GtkWidget *spin;
624 spin = create_spin("SidReSidFilterBias", -5000, 5000, 1, slider);
625
626 g_signal_connect(
627 spin,
628 "value-changed",
629 G_CALLBACK(on_resid_6581_bias_spin_change),
630 NULL);
631 return spin;
632 }
633
634
635 /** \brief Create scale to control the "SidResidGain" resource
636 *
637 * \return GtkScale
638 */
create_resid_6581_gain_widget(void)639 static GtkWidget *create_resid_6581_gain_widget(void)
640 {
641 GtkWidget *scale;
642
643 scale = vice_gtk3_resource_scale_int_new("SidResidGain",
644 GTK_ORIENTATION_HORIZONTAL, 90, 100, 1);
645
646 g_signal_connect(scale, "value-changed",
647 G_CALLBACK(on_resid_6581_gain_change),
648 NULL);
649 return scale;
650 }
651
652
653 /** \brief Create scale to control the "SidResidFilterBias" resource
654 *
655 * \return GtkScale
656 */
create_resid_6581_bias_widget(void)657 static GtkWidget *create_resid_6581_bias_widget(void)
658 {
659 GtkWidget *scale;
660
661 scale = vice_gtk3_resource_scale_int_new("SidResidFilterBias",
662 GTK_ORIENTATION_HORIZONTAL, -5000, 5000, 1);
663 g_signal_connect(scale, "value-changed",
664 G_CALLBACK(on_resid_6581_bias_change),
665 NULL);
666 return scale;
667 }
668
669 /** \brief Create scale to control the "SidResid8580Passband" resource
670 *
671 * \return GtkScale
672 */
create_resid_8580_passband_widget(void)673 static GtkWidget *create_resid_8580_passband_widget(void)
674 {
675 GtkWidget *scale;
676
677 scale = vice_gtk3_resource_scale_int_new("SidResid8580Passband",
678 GTK_ORIENTATION_HORIZONTAL, 0, 90, 1);
679 return scale;
680 }
681
682
683 /** \brief Create scale to control the "SidResid8580Gain" resource
684 *
685 * \return GtkScale
686 */
create_resid_8580_gain_widget(void)687 static GtkWidget *create_resid_8580_gain_widget(void)
688 {
689 GtkWidget *scale;
690
691 scale = vice_gtk3_resource_scale_int_new("SidResid8580Gain",
692 GTK_ORIENTATION_HORIZONTAL, 90, 100, 1);
693 return scale;
694 }
695
696
697 /** \brief Create scale to control the "SidResid8580FilterBias" resource
698 *
699 * \return GtkScale
700 */
create_resid_8580_bias_widget(void)701 static GtkWidget *create_resid_8580_bias_widget(void)
702 {
703 GtkWidget *scale;
704
705 scale = vice_gtk3_resource_scale_int_new("SidResid8580FilterBias",
706 GTK_ORIENTATION_HORIZONTAL, -5000, 5000, 1);
707 /* vice_gtk3_resource_scale_int_set_marks(scale, 500); */
708 return scale;
709 }
710 #endif
711
712
713 #ifdef HAVE_RESID
714 /** \brief Create "Reset to default" button
715 *
716 * \param[in] callback callback for the button
717 *
718 * \return GtkButton
719 */
create_resource_reset_button(void (* callback)(GtkWidget *,gpointer))720 static GtkWidget *create_resource_reset_button(
721 void (*callback)(GtkWidget *, gpointer))
722 {
723 GtkWidget *button;
724
725 button = gtk_button_new_with_label("Reset");
726 gtk_widget_set_valign(button, GTK_ALIGN_END);
727 gtk_widget_set_hexpand(button, FALSE);
728 g_object_set(button, "margin-left", 16, NULL);
729
730 g_signal_connect(button, "clicked", G_CALLBACK(callback), NULL);
731
732 gtk_widget_show(button);
733 return button;
734 }
735 #endif
736
737
738 /** \brief Create widget to control SID settings
739 *
740 * \param[in] parent parent widget
741 *
742 * \return GtkGrid
743 */
sid_sound_widget_create(GtkWidget * parent)744 GtkWidget *sid_sound_widget_create(GtkWidget *parent)
745 {
746 GtkWidget *layout;
747 GtkWidget *label;
748 GtkWidget *engine;
749 GtkWidget *sids = NULL;
750 int current_engine;
751 int stereo;
752 int row = 2;
753 int i;
754 int model;
755 #ifdef HAVE_RESID
756 int is_resid;
757 #endif
758
759 layout = gtk_grid_new();
760 gtk_grid_set_column_spacing(GTK_GRID(layout), 8);
761 gtk_grid_set_row_spacing(GTK_GRID(layout), 8);
762
763 label = gtk_label_new(NULL);
764 gtk_label_set_markup(GTK_LABEL(label), "<b>SID settings</b>");
765 gtk_widget_set_halign(label, GTK_ALIGN_START);
766 gtk_grid_attach(GTK_GRID(layout), label, 0, 0, 3, 1);
767
768 if (resources_get_int("SidModel", &model) < 0) {
769 debug_gtk3("failed to get SidModel resource");
770 }
771
772 engine = sid_engine_model_widget_create();
773 sid_engine_model_widget_set_callback(engine, engine_model_changed_callback);
774 gtk_grid_attach(GTK_GRID(layout), engine, 0, 1, 1,1);
775 #ifdef HAVE_RESID
776 resid_sampling = create_resid_sampling_widget();
777 gtk_grid_attach(GTK_GRID(layout), resid_sampling, 1, 1, 1, 1);
778 #endif
779 resources_get_int("SidEngine", ¤t_engine);
780 debug_gtk3("SidEngine = %d.", current_engine);
781 #ifdef HAVE_RESID
782 is_resid = current_engine == SID_ENGINE_RESID;
783 #endif
784
785 if (sid_machine_can_have_multiple_sids()) {
786 int max = sid_machine_get_max_sids();
787 int c = 1;
788 GtkWidget *sid_addresses;
789
790 sids = create_num_sids_widget();
791 gtk_grid_attach(GTK_GRID(layout), sids, 2, 1, 1, 1);
792
793 for (i = 1; i < max; i++) {
794
795 address_widgets[i - 1] = create_extra_sid_address_widget(i);
796 }
797
798 sid_addresses = vice_gtk3_grid_new_spaced_with_label(
799 16, 8, "SID I/O addresses", 3);
800 g_object_set(sid_addresses,
801 "margin-left", 16,
802 "margin-top", 16,
803 "margin-bottom", 16,
804 NULL);
805
806 /* lay out address widgets in a grid of four columns max, skip the
807 * first SID
808 */
809 i = 0;
810 while (i < max - 1) {
811 while ((c < 4) && (i < max -1)) {
812 debug_gtk3("Adding address widget #%d", i);
813 gtk_grid_attach(GTK_GRID(sid_addresses),
814 address_widgets[i],
815 c, ((i + 1) / 4) + 1, 1, 1);
816 c++;
817 i++;
818 }
819 c = 0;
820 }
821 gtk_grid_attach(GTK_GRID(layout), sid_addresses, 0, row++, 3, 1);
822 } else {
823 row = 2;
824 }
825
826 #ifdef HAVE_RESID
827 filters = vice_gtk3_resource_check_button_new("SidFilters",
828 "Enable SID filter emulation");
829 gtk_grid_attach(GTK_GRID(layout), filters, 0, row, 3, 1);
830 #endif
831
832 #ifdef HAVE_RESID
833 gtk_widget_set_sensitive(resid_sampling, current_engine == SID_ENGINE_RESID);
834 gtk_widget_set_sensitive(filters, current_engine == SID_ENGINE_RESID);
835 #endif
836
837
838 #ifdef HAVE_RESID
839 /* TODO: check engine as well (hardSID)
840 * Also somehow delete and replace 6581/8580 mixer widget when
841 * changing model, so this has to go, mostly.
842 */
843
844 resid_6581_grid = gtk_grid_new();
845 resid_8580_grid = gtk_grid_new();
846 g_object_set(resid_6581_grid, "margin", 0, NULL);
847 g_object_set(resid_8580_grid, "margin", 0, NULL);
848
849 /* 8580 */
850
851 label = gtk_label_new(NULL);
852 gtk_label_set_markup(GTK_LABEL(label), "<b>ReSID 8580 filter settings</b>");
853 gtk_widget_show(label);
854 gtk_grid_attach(GTK_GRID(resid_8580_grid), label, 0, 0, 3, 1);
855
856 /* 8580 passband */
857 label = gtk_label_new("8580 passband");
858 gtk_widget_set_halign(label, GTK_ALIGN_START);
859 g_object_set(label, "margin-left", 16, NULL);
860 resid_8580_passband = create_resid_8580_passband_widget();
861 resid_8580_passband_button = create_resource_reset_button(
862 on_resid_8580_passband_default_clicked);
863 gtk_grid_attach(GTK_GRID(resid_8580_grid),
864 label, 0, 1, 1, 1);
865 gtk_grid_attach(GTK_GRID(resid_8580_grid),
866 resid_8580_passband, 1, 1, 1, 1);
867 gtk_grid_attach(GTK_GRID(resid_8580_grid),
868 resid_8580_passband_button, 3, 1, 1, 1);
869
870 /* We need to do this due to show_all getting disabled for the containing
871 * GtkGrid and the other widgets (slider, button) having their own call
872 * to Show() except this simple label:
873 */
874 gtk_widget_show(label);
875
876 /* 8580 gain */
877 label = gtk_label_new("8580 gain");
878 gtk_widget_set_halign(label, GTK_ALIGN_START);
879 g_object_set(label, "margin-left", 16, NULL);
880 resid_8580_gain = create_resid_8580_gain_widget();
881 resid_8580_gain_button = create_resource_reset_button(
882 on_resid_8580_gain_default_clicked);
883 gtk_grid_attach(GTK_GRID(resid_8580_grid),
884 label, 0, 2, 1, 1);
885 gtk_grid_attach(GTK_GRID(resid_8580_grid),
886 resid_8580_gain, 1, 2, 1, 1);
887 gtk_grid_attach(GTK_GRID(resid_8580_grid),
888 resid_8580_gain_button, 3, 2, 1, 1);
889 gtk_widget_show(label);
890
891 /* 8580 bias */
892 label = gtk_label_new("8580 filter bias");
893 gtk_widget_set_halign(label, GTK_ALIGN_START);
894 g_object_set(label, "margin-left", 16, NULL);
895 resid_8580_bias = create_resid_8580_bias_widget();
896 resid_8580_bias_button = create_resource_reset_button(
897 on_resid_8580_bias_default_clicked);
898 gtk_grid_attach(GTK_GRID(resid_8580_grid),
899 label, 0, 3, 1, 1);
900 gtk_grid_attach(GTK_GRID(resid_8580_grid),
901 resid_8580_bias, 1, 3, 1, 1);
902 gtk_grid_attach(GTK_GRID(resid_8580_grid),
903 resid_8580_bias_button, 3, 3, 1, 1);
904 gtk_widget_show(label);
905
906 /* 6581 (YAY!) */
907
908 label = gtk_label_new(NULL);
909 gtk_label_set_markup(GTK_LABEL(label), "<b>ReSID 6581 filter settings</b>");
910 gtk_widget_show(label);
911 gtk_grid_attach(GTK_GRID(resid_6581_grid), label, 0, 0, 3, 1);
912
913 /* 6581 passband */
914 label = gtk_label_new("6581 passband");
915 gtk_widget_set_halign(label, GTK_ALIGN_START);
916 g_object_set(label, "margin-left", 16, NULL);
917 resid_6581_passband = create_resid_6581_passband_widget();
918 resid_6581_passband_button = create_resource_reset_button(
919 on_resid_6581_passband_default_clicked);
920 resid_6581_passband_spin = create_resid_6581_passband_spin(resid_6581_passband);
921 gtk_grid_attach(GTK_GRID(resid_6581_grid),
922 label, 0, 1, 1, 1);
923 gtk_grid_attach(GTK_GRID(resid_6581_grid),
924 resid_6581_passband, 1, 1, 1, 1);
925 gtk_grid_attach(GTK_GRID(resid_6581_grid),
926 resid_6581_passband_spin, 2, 1, 1, 1);
927 gtk_grid_attach(GTK_GRID(resid_6581_grid),
928 resid_6581_passband_button, 3, 1, 1, 1);
929 gtk_widget_show(label);
930
931 /* 6581 gain */
932 label = gtk_label_new("6581 gain");
933 gtk_widget_set_halign(label, GTK_ALIGN_START);
934 g_object_set(label, "margin-left", 16, NULL);
935 resid_6581_gain = create_resid_6581_gain_widget();
936 resid_6581_gain_button = create_resource_reset_button(
937 on_resid_6581_gain_default_clicked);
938 resid_6581_gain_spin = create_resid_6581_gain_spin(resid_6581_gain);
939 gtk_grid_attach(GTK_GRID(resid_6581_grid),
940 label, 0, 2, 1, 1);
941 gtk_grid_attach(GTK_GRID(resid_6581_grid),
942 resid_6581_gain, 1, 2, 1, 1);
943 gtk_grid_attach(GTK_GRID(resid_6581_grid),
944 resid_6581_gain_spin, 2, 2, 1, 1);
945 gtk_grid_attach(GTK_GRID(resid_6581_grid),
946 resid_6581_gain_button, 3, 2, 1, 1);
947 gtk_widget_show(label);
948
949 /* 6581 bias */
950 label = gtk_label_new("6581 filter bias");
951 gtk_widget_set_halign(label, GTK_ALIGN_START);
952 g_object_set(label, "margin-left", 16, NULL);
953 resid_6581_bias = create_resid_6581_bias_widget();
954 resid_6581_bias_button = create_resource_reset_button(
955 on_resid_6581_bias_default_clicked);
956 resid_6581_bias_spin = create_resid_6581_bias_spin(resid_6581_bias);
957 gtk_grid_attach(GTK_GRID(resid_6581_grid),
958 label, 0, 3, 1, 1);
959 gtk_grid_attach(GTK_GRID(resid_6581_grid),
960 resid_6581_bias, 1, 3, 1, 1);
961 gtk_grid_attach(GTK_GRID(resid_6581_grid),
962 resid_6581_bias_spin, 2, 3, 1, 1);
963 gtk_grid_attach(GTK_GRID(resid_6581_grid),
964 resid_6581_bias_button, 3, 3, 1, 1);
965 gtk_widget_show(label);
966
967 /* force expansion */
968 gtk_widget_set_hexpand(resid_6581_gain, TRUE);
969 gtk_widget_set_hexpand(resid_8580_gain, TRUE);
970
971 debug_gtk3("Adding 6581/8580 ReSID widgets.");
972 gtk_widget_set_hexpand(resid_6581_grid, TRUE);
973 gtk_grid_attach(GTK_GRID(layout), resid_6581_grid, 0, row + 1, 3 ,1);
974 gtk_grid_attach(GTK_GRID(layout), resid_8580_grid, 0, row + 2, 3, 1);
975
976 #endif
977
978 if (machine_class != VICE_MACHINE_PLUS4
979 && machine_class != VICE_MACHINE_CBM5x0
980 && machine_class != VICE_MACHINE_CBM6x0)
981 {
982 /* set sensitivity of address widgets */
983 resources_get_int("SidStereo", &stereo);
984 on_sid_count_changed(NULL, GINT_TO_POINTER(stereo));
985 }
986
987 #ifdef HAVE_RESID
988 /* only enable proper widgets */
989 gtk_widget_set_no_show_all(resid_6581_grid, TRUE);
990 gtk_widget_set_no_show_all(resid_8580_grid, TRUE);
991 if (model == 1 || model == 2) {
992 gtk_widget_show(resid_8580_grid);
993 gtk_widget_hide(resid_6581_grid);
994 } else {
995 gtk_widget_show(resid_6581_grid);
996 gtk_widget_hide(resid_8580_grid);
997 }
998
999 gtk_widget_set_sensitive(resid_6581_grid, is_resid);
1000 gtk_widget_set_sensitive(resid_8580_grid, is_resid);
1001 #endif
1002 gtk_widget_show_all(layout);
1003
1004 return layout;
1005 }
1006