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", &current_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