1 
2 /*
3  * The Real SoundTracker - sample editor
4  *
5  * Copyright (C) 1998-2019 Michael Krause
6  * Copyright (C) 2020, 2021 Yury Aliaev
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  */
22 
23 #include <config.h>
24 
25 #include <stdio.h>
26 #include <string.h>
27 
28 #include <fcntl.h>
29 #include <math.h>
30 #include <stdlib.h>
31 #include <sys/ioctl.h>
32 #include <unistd.h>
33 #include <math.h>
34 
35 #if USE_SNDFILE
36 #include <sndfile.h>
37 #elif AUDIOFILE_VERSION
38 #include <audiofile.h>
39 #endif
40 
41 #include <gdk/gdkkeysyms.h>
42 #include <glib/gprintf.h>
43 #include <glib/gi18n.h>
44 #include <gtk/gtk.h>
45 
46 #include "audio.h"
47 #include "clock.h"
48 #include "colors.h"
49 #include "draw-interlayer.h"
50 #include "endian-conv.h"
51 #include "errors.h"
52 #include "file-operations.h"
53 #include "gui-settings.h"
54 #include "gui-subs.h"
55 #include "gui.h"
56 #include "history.h"
57 #include "instrument-editor.h"
58 #include "keys.h"
59 #include "mixer.h"
60 #include "module-info.h"
61 #include "sample-display.h"
62 #include "sample-editor.h"
63 #include "st-subs.h"
64 #include "time-buffer.h"
65 #include "track-editor.h"
66 #include "xm.h"
67 
68 // == GUI variables
69 
70 /* Dimensions and position of the record indicator:
71     size = MAX(MIN_SIZE, MIN(window_width, window_height) / FRACTION_S)
72     space between window sides and the indicator is calculated similarly
73     to that in scope-group.h (with FRACRION_D as FRACTION) */
74 static const guint MIN_SIZE = 10, XDISP = 3, YDISP = 3, FRACTION_S = 20, FRACTION_D = 100;
75 
76 static STSample *current_sample = NULL, *tmp_sample = NULL;
77 
78 static GtkWidget* se_spins[SAMPLE_EDITOR_SPIN_LAST];
79 static SampleDisplay* sampledisplay;
80 static GtkWidget* sample_editor_hscrollbar;
81 static GtkWidget *loopradio[3], *resolution_radio[2], *record_radio[4];
82 #if USE_SNDFILE || AUDIOFILE_VERSION
83 static GtkWidget *load_radio[4];
84 #endif
85 static GtkWidget *spin_loopstart, *spin_loopend;
86 static GSList* list_data_sensitive = NULL;
87 
88 static guint scrollbar_cb_tag;
89 static gint tags[SAMPLE_EDITOR_SPIN_LAST], tag_loopstart, tag_loopend;
90 
91 #if USE_SNDFILE || AUDIOFILE_VERSION
92 static file_op *loadsmp, *savesmp, *savereg;
93 #endif
94 
95 static gint last_xpos = 0;
96 static gboolean cursor_in = FALSE;
97 static gboolean copy_whole_sample = FALSE;
98 
99 static GtkWidget* sample_editor_volramp_spin_w[2];
100 
101 enum {
102     MODE_MONO = 0,
103     MODE_STEREO_MIX,
104     MODE_STEREO_LEFT,
105     MODE_STEREO_RIGHT,
106     MODE_STEREO_2
107 };
108 
109 #if USE_SNDFILE || AUDIOFILE_VERSION
110 static GtkWidget* wavload_dialog;
111 
112 struct wl {
113     gboolean through_library;
114     const char* samplename;
115 
116 #if USE_SNDFILE
117     SNDFILE* file;
118     SF_INFO wavinfo;
119     sf_count_t frameCount;
120 #else
121     AFfilehandle file;
122     AFframecount frameCount;
123 #endif
124 
125     int sampleWidth, channelCount, endianness, unsignedwords;
126     long rate;
127 };
128 
129 static GtkWidget* wavload_raw_resolution_w[2];
130 static GtkWidget* wavload_raw_channels_w[2];
131 static GtkWidget* wavload_raw_signed_w[2];
132 static GtkWidget* wavload_raw_endian_w[2];
133 #endif
134 
135 // = Sampler variables
136 
137 static SampleDisplay* monitorscope = NULL;
138 static DIGC mask_gc, mask_bg_gc, red_circle_gc;
139 static GtkWidget *clearbutton, *okbutton, *sclock;
140 static void *monitor_buf = NULL;
141 
142 st_driver* sampling_driver = NULL;
143 void* sampling_driver_object = NULL;
144 
145 static GtkWidget* samplingwindow = NULL;
146 
147 static STSampleChain *recordbufs, *current = NULL;
148 static guint recordedlen, rate, toggled_id, monitor_count;
149 static gboolean sampling, monitoring, has_data;
150 static STMixerFormat format;
151 
152 // = Editing operations variables
153 
154 static void* copybuffer = NULL;
155 static int copybufferlen;
156 static STSample copybuffer_sampleinfo;
157 
158 // = Realtime stuff
159 
160 static int gtktimer = -1;
161 
162 static void sample_editor_ok_clicked(void);
163 
164 static void sample_editor_spin_volume_changed(GtkSpinButton* spin);
165 static void sample_editor_spin_panning_changed(GtkSpinButton* spin);
166 static void sample_editor_spin_finetune_changed(GtkSpinButton* spin);
167 static void sample_editor_spin_relnote_changed(GtkSpinButton* spin);
168 static void sample_editor_loop_changed(GtkSpinButton* spin, gpointer data);
169 static void sample_editor_display_loop_changed(SampleDisplay*, int start, int end);
170 static void sample_editor_display_selection_changed(SampleDisplay*, int start, int end);
171 static void sample_editor_display_window_changed(GtkAdjustment*, int start, int end, SampleDisplay* s);
172 static void sample_editor_display_position_changed(GtkAdjustment*, int pos);
173 static void sample_editor_loopradio_changed(GtkToggleButton* tb);
174 void sample_editor_paste_clicked(void);
175 void sample_editor_zoom_in_clicked(void);
176 void sample_editor_zoom_out_clicked(void);
177 
178 #if USE_SNDFILE || AUDIOFILE_VERSION
179 static void sample_editor_load_wav(const gchar* name, const gchar* localname);
180 static void sample_editor_save_wav(const gchar* name, const gchar* localname);
181 static void sample_editor_save_region_wav(const gchar* name, const gchar* localname);
182 #endif
183 
184 static void sample_editor_trim(gboolean beg, gboolean end, gfloat threshold);
185 static void sample_editor_delete(STSample* sample, int start, int end);
186 
187 static void
sample_editor_lock_sample(void)188 sample_editor_lock_sample(void)
189 {
190     g_mutex_lock(&current_sample->sample.lock);
191 }
192 
193 static void
sample_editor_unlock_sample(void)194 sample_editor_unlock_sample(void)
195 {
196     if (gui_playing_mode) {
197         mixer->updatesample(&current_sample->sample);
198     }
199     g_mutex_unlock(&current_sample->sample.lock);
200 }
201 
202 void
sample_editor_update_status(void)203 sample_editor_update_status(void)
204 {
205     if (notebook_current_page == NOTEBOOK_PAGE_SAMPLE_EDITOR) {
206         static gchar se_status[256];
207         gint n;
208         gint ss = sampledisplay->sel_start;
209         gint se = sampledisplay->sel_end;
210 
211         n = snprintf(se_status, sizeof(se_status),
212             _("[Length: %i]"), current_sample->sample.length);
213         if (cursor_in && current_sample->sample.data)
214             n += snprintf(&se_status[n], sizeof(se_status) - n,
215                 _(" [Position: %i]"),
216                 sample_display_xpos_to_offset(sampledisplay, last_xpos));
217         if (ss != -1)
218             snprintf(&se_status[n], sizeof(se_status) - n,
219                 _(" [Selection: %i \342\200\223 %i (%i discretes)]"),
220                 ss, se, se - ss);
221         gui_statusbar_update_message_high(se_status);
222     }
223 }
224 
225 static gboolean
sample_editor_display_scrolled(GtkAdjustment * adj,GdkEventScroll * event)226 sample_editor_display_scrolled(GtkAdjustment *adj,
227    GdkEventScroll *event)
228 {
229     gboolean handled = FALSE;
230     gdouble value, incr, pincr, lower, upper, psize;
231 
232     if (current_sample == NULL || current_sample->sample.data == NULL)
233         return handled;
234     if (sampledisplay->win_start == 0 &&
235         sampledisplay->win_length == current_sample->sample.length &&
236         !((event->direction == GDK_SCROLL_DOWN || event->direction == GDK_SCROLL_RIGHT)
237             && event->state & GDK_CONTROL_MASK))
238         return handled;
239 
240     value = gtk_adjustment_get_value(adj);
241     incr = gtk_adjustment_get_step_increment(adj);
242     pincr = gtk_adjustment_get_page_increment(adj);
243     psize = gtk_adjustment_get_page_size(adj);
244     lower = gtk_adjustment_get_lower(adj);
245     upper = gtk_adjustment_get_upper(adj);
246 
247     switch (event->direction) {
248     case GDK_SCROLL_UP:
249     case GDK_SCROLL_LEFT:
250         if (event->state & GDK_CONTROL_MASK)
251             sample_editor_zoom_out_clicked();
252         else {
253             value -= ((event->state & GDK_SHIFT_MASK) ? pincr : incr);
254             gtk_adjustment_set_value(adj, CLAMP(value, lower, upper - psize));
255         }
256         handled = TRUE;
257         break;
258     case GDK_SCROLL_DOWN:
259     case GDK_SCROLL_RIGHT:
260         if (event->state & GDK_CONTROL_MASK)
261             sample_editor_zoom_in_clicked();
262         else {
263             value += ((event->state & GDK_SHIFT_MASK) ? pincr : incr);
264             gtk_adjustment_set_value(adj, CLAMP(value, lower, upper - psize));
265         }
266         handled = TRUE;
267         break;
268     default:
269         break;
270     }
271 
272     last_xpos = event->x;
273     sample_editor_update_status();
274 
275     return handled;
276 }
277 
278 static void
sample_editor_hscrollbar_changed(GtkAdjustment * adj)279 sample_editor_hscrollbar_changed (GtkAdjustment *adj)
280 {
281     sample_display_set_window(sampledisplay, rint(gtk_adjustment_get_value(adj)), -1);
282 }
283 
284 static void
red_circle_realize(GtkWidget * widget,gpointer data)285 red_circle_realize(GtkWidget* widget, gpointer data)
286 {
287     static gboolean firsttime = TRUE;
288 
289     if (firsttime) {
290         mask_gc = di_gc_new(widget->window);
291         mask_bg_gc = colors_get_gc(COLOR_BLACK);
292         red_circle_gc = colors_get_gc(COLOR_RED);
293     }
294 }
295 
296 static void
red_circle_draw(GtkWidget * widget,GdkRectangle * area,gpointer data)297 red_circle_draw(GtkWidget* widget, GdkRectangle* area, gpointer data)
298 {
299     if (sampling) {
300         static gint width = -1, height = -1;
301         static guint oldsize = 0;
302         static GdkPixmap* red_circle_pm = NULL;
303         static DIDrawable red_circle_drw;
304 
305         guint size = MAX(MIN_SIZE, MIN(widget->allocation.width, widget->allocation.height) / FRACTION_S);
306         guint x0 = widget->allocation.width - XDISP - widget->allocation.width / FRACTION_D - size;
307         guint y0 = YDISP + widget->allocation.height / FRACTION_D;
308         GdkRectangle dest_area;
309         DIDrawable win = custom_drawing_get_drawable(CUSTOM_DRAWING(widget));
310 
311         dest_area.x = x0;
312         dest_area.y = y0;
313         dest_area.width = size;
314         dest_area.height = size;
315 
316         /* Update number mask if necessary */
317         if (widget->allocation.width != width || widget->allocation.height != height || (!red_circle_pm)) {
318             width = widget->allocation.width;
319             height = widget->allocation.height;
320 
321             /* The indicator itself is to be redrawn */
322             if (!red_circle_pm || oldsize != size) {
323                 oldsize = size;
324 
325                 if (red_circle_pm)
326                     g_object_unref(red_circle_pm);
327                 red_circle_pm = gdk_pixmap_new(widget->window, size, size, -1);
328                 red_circle_drw = di_get_drawable(red_circle_pm);
329 
330                 di_draw_rectangle(red_circle_drw, mask_bg_gc, TRUE, 0, 0, size, size);
331                 di_draw_arc(red_circle_drw, red_circle_gc, TRUE, 0, 0, size, size, 0, 360 * 64);
332             }
333             di_update_mask(widget->window, red_circle_pm, mask_gc, x0, y0, size, size, width, height);
334         }
335 
336         if (gdk_rectangle_intersect(area, &dest_area, &dest_area))
337             di_draw_drawable(win, mask_gc, red_circle_drw,
338                 dest_area.x - x0, dest_area.y - y0,
339                 dest_area.x, dest_area.y, dest_area.width, dest_area.height);
340     }
341 }
342 
343 static gboolean
sample_display_cursor_motion(GtkWidget * w,GdkEventMotion * event)344 sample_display_cursor_motion(GtkWidget* w, GdkEventMotion* event)
345 {
346     g_assert(IS_SAMPLE_DISPLAY(w));
347 
348     last_xpos = event->x;
349     sample_editor_update_status();
350 
351     return FALSE;
352 }
353 
354 static gboolean
sample_display_border_cross(GtkWidget * w,GdkEventCrossing * event,gpointer p)355 sample_display_border_cross(GtkWidget* w, GdkEventCrossing* event, gpointer p)
356 {
357     cursor_in = GPOINTER_TO_INT(p);
358     last_xpos = event->x;
359     sample_editor_update_status();
360 
361     return FALSE;
362 }
363 
364 static void
sample_editor_blocked_set_display_loop(int start,int end)365 sample_editor_blocked_set_display_loop(int start,
366     int end)
367 {
368     g_signal_handlers_block_by_func(G_OBJECT(sampledisplay), G_CALLBACK(sample_editor_display_loop_changed), NULL);
369     sample_display_set_loop(sampledisplay, start, end);
370     g_signal_handlers_unblock_by_func(G_OBJECT(sampledisplay), G_CALLBACK(sample_editor_display_loop_changed), NULL);
371 }
372 
373 static void
sample_editor_block_loop_spins(gboolean block)374 sample_editor_block_loop_spins(gboolean block)
375 {
376     if (block) {
377         g_signal_handler_block(G_OBJECT(spin_loopstart), tag_loopstart);
378         g_signal_handler_block(G_OBJECT(spin_loopend), tag_loopend);
379     } else {
380         g_signal_handler_unblock(G_OBJECT(spin_loopstart), tag_loopstart);
381         g_signal_handler_unblock(G_OBJECT(spin_loopend), tag_loopend);
382     }
383 }
384 
385 static void
sample_editor_loop_changed(GtkSpinButton * spin,gpointer data)386 sample_editor_loop_changed(GtkSpinButton* spin, gpointer data)
387 {
388     st_mixer_sample_info *s;
389     const gint new_v = gtk_spin_button_get_value_as_int(spin);
390     const gboolean is_end = GPOINTER_TO_INT(data);
391     guint32* v;
392 
393     g_return_if_fail(current_sample != NULL);
394     g_return_if_fail(current_sample->sample.data != NULL);
395 
396     s = &current_sample->sample;
397     v = is_end ? &s->loopend : &s->loopstart;
398     if (*v == new_v)
399         return;
400 
401     history_log_spin_button(spin, _(is_end ? N_("Sample loop end setting") : N_("Sample loop start setting")),
402         HISTORY_FLAG_LOG_ALL, *v);
403     sample_editor_lock_sample();
404     *v = new_v;
405     sample_editor_unlock_sample();
406 
407     if (is_end)
408         gtk_spin_button_set_range(GTK_SPIN_BUTTON(spin_loopstart), 0, s->length ? new_v - 1 : 0);
409     else
410         gtk_spin_button_set_range(GTK_SPIN_BUTTON(spin_loopend), s->length ? new_v + 1 : 1, s->length);
411     if (current_sample->sample.looptype != ST_MIXER_SAMPLE_LOOPTYPE_NONE)
412         sample_editor_blocked_set_display_loop(s->loopstart, s->loopend);
413 }
414 
415 static void
sample_editor_resolution_changed(GtkToggleButton * tb)416 sample_editor_resolution_changed(GtkToggleButton* tb)
417 {
418     STSample* sts = current_sample;
419     gint n, old_v;
420 
421     if (!gtk_toggle_button_get_active(tb))
422         return;
423     if (!sts)
424         return;
425     n = find_current_toggle(resolution_radio, 2);
426     old_v = sts->treat_as_8bit ? 0 : 1;
427     if (n == old_v)
428         return;
429 
430     history_log_radio_group(resolution_radio, _("Sample resolution setting"),
431         HISTORY_FLAG_LOG_ALL, sts->treat_as_8bit ? 0 : 1, 2);
432     sts->treat_as_8bit = (n == 0);
433 }
434 
sample_editor_page_create(GtkNotebook * nb)435 void sample_editor_page_create(GtkNotebook* nb)
436 {
437     GtkWidget *box, *thing, *hbox;
438     GtkAdjustment *adj;
439     GtkBuilder* builder;
440     GtkAccelGroup *accel_group;
441     gint i;
442 
443     static const char* looplabels[] = {
444         N_("No loop"),
445         N_("Amiga"),
446         N_("PingPong")
447     };
448     static const char* resolutionlabels[] = {
449         N_("8 bits"),
450         N_("16 bits")
451     };
452 
453 #if USE_SNDFILE || AUDIOFILE_VERSION
454     static const gchar* aiff_f[] = { N_("Apple/SGI audio (*aif, *.aiff, *.aifc)"), "*.[aA][iI][fF]", "*.[aA][iI][fF][fFcC]", NULL };
455     static const gchar* au_f[] = { N_("SUN/NeXT audio (*.au, *.snd)"), "*.[aA][uU]", "*.[sS][nN][dD]", NULL };
456     static const gchar* avr_f[] = { N_("Audio Visual Research files (*.avr)"), "*.[aA][vV][rR]", NULL };
457     static const gchar* caf_f[] = { N_("Apple Core Audio files (*.caf)"), "*.[cC][aA][fF]", NULL };
458     static const gchar* iff_f[] = { N_("Amiga IFF/SV8/SV16 (*.iff)"), "*.[iI][fF][fF]", NULL };
459     static const gchar* sf_f[] = { N_("Berkeley/IRCAM/CARL audio (*.sf)"), "*.[sS][fF]", NULL };
460     static const gchar* voc_f[] = { N_("Creative Labs audio (*.voc)"), "*.[vV][oO][cC]", NULL };
461     static const gchar* wavex_f[] = { N_("Microsoft RIFF/NIST Sphere (*.wav)"), "*.[wW][aA][vV]", NULL };
462     static const gchar* flac_f[] = { N_("FLAC lossless audio (*.flac)"), "*.flac", NULL };
463     static const gchar* wve_f[] = { N_("Psion audio (*.wve)"), "*.wve", NULL };
464     static const gchar* ogg_f[] = { N_("OGG compressed audio (*.ogg, *.vorbis)"), "*.ogg", "*.vorbis", NULL };
465     static const gchar* rf64_f[] = { N_("RIFF 64 files (*.rf64)"), "*.rf64", NULL };
466 
467     static const gchar* wav_f[] = { N_("Microsoft RIFF (*.wav)"), "*.[wW][aA][vV]", NULL };
468     static const gchar** out_f[] = { wav_f, NULL };
469 #endif
470 
471 #if USE_SNDFILE
472     static const gchar* htk_f[] = { N_("HMM Tool Kit files (*.htk)"), "*.[hH][tT][kK]", NULL };
473     static const gchar* mat_f[] = { N_("GNU Octave/Matlab files (*.mat)"), "*.[mM][aA][tT]", NULL };
474     static const gchar* paf_f[] = { N_("Ensoniq PARIS files (*.paf)"), "*.[pP][aA][fF]", NULL };
475     static const gchar* pvf_f[] = { N_("Portable Voice Format files (*.pvf)"), "*.[pP][vV][fF]", NULL };
476     static const gchar* raw_f[] = { N_("Headerless raw data (*.raw, *.r8)"), "*.[rR][aA][wW]", "*.[rR]8", NULL };
477     static const gchar* sd2_f[] = { N_("Sound Designer II files (*.sd2)"), "*.[sS][dD]2", NULL };
478     static const gchar* sds_f[] = { N_("Midi Sample Dump Standard files (*.sds)"), "*.[sS][dD][sS]", NULL };
479     static const gchar* w64_f[] = { N_("SoundFoundry WAVE 64 files (*.w64)"), "*.[wW]64", NULL };
480 
481     static const gchar** in_f[] = { aiff_f, au_f, avr_f, caf_f, htk_f, iff_f, mat_f, paf_f, pvf_f, raw_f, sd2_f, sds_f, sf_f,
482         voc_f, w64_f, wavex_f, flac_f, wve_f, ogg_f, rf64_f, NULL };
483 #endif
484 
485 #if !USE_SNDFILE && AUDIOFILE_VERSION
486     static const gchar* smp_f[] = { N_("Sample Vision files (*.smp)"), "*.[sS][mM][pP]", NULL };
487 
488     static const gchar** in_f[] = { aiff_f, au_f, avr_f, caf_f, iff_f, sf_f, voc_f, wavex_f, smp_f, rf64_f, ogg_f,
489         wve_f, flac_f, NULL };
490 #endif
491 
492     const icon_set sample_editor_icons[] =
493         {{"st-select-all", "select-all", SIZES_MENU_TOOLBOX},
494          {"st-select-none", "select-none", SIZES_MENU_TOOLBOX},
495          {"st-crop", "crop", SIZES_MENU},
496          {NULL}};
497 
498 #if USE_SNDFILE || AUDIOFILE_VERSION
499     loadsmp = fileops_dialog_create(DIALOG_LOAD_SAMPLE, _("Load Sample"), &gui_settings.loadsmpl_path, sample_editor_load_wav, TRUE, FALSE, in_f, N_("Load sample into the current sample slot"), NULL);
500     savesmp = fileops_dialog_create(DIALOG_SAVE_SAMPLE, _("Save Sample"), &gui_settings.savesmpl_path, sample_editor_save_wav, TRUE, TRUE, out_f, N_("Save the current sample"), "wav");
501     savereg = fileops_dialog_create(DIALOG_SAVE_RGN_SAMPLE, _("Save region as WAV..."), &gui_settings.savesmpl_path, sample_editor_save_region_wav, FALSE, TRUE, out_f, NULL, "wav");
502 #endif
503 
504     gui_add_icons(sample_editor_icons);
505 
506     box = gtk_vbox_new(FALSE, 2);
507     gtk_container_set_border_width(GTK_CONTAINER(box), 10);
508     gtk_notebook_append_page(nb, box, gtk_label_new(_("Sample Editor")));
509     gtk_widget_show(box);
510 
511 #define S_E_XML DATADIR "/" PACKAGE "/sample-editor.xml"
512     builder = gui_builder_from_file(S_E_XML, NULL);
513     thing = gui_get_widget(builder, "sample_editor_menu", S_E_XML);
514     gtk_box_pack_start(GTK_BOX(box), thing, FALSE, FALSE, 0);
515     thing = gui_get_widget(builder, "sample_editor_toolbar", S_E_XML);
516     gtk_box_pack_start(GTK_BOX(box), thing, FALSE, FALSE, 0);
517     thing = gui_get_widget(builder, "selection_menu", S_E_XML);
518     list_data_sensitive = g_slist_prepend(list_data_sensitive, thing);
519 
520     struct {
521         const gchar* const title;
522         guint key;
523         GdkModifierType mods;
524     } accel_list[] = {
525         {"zoom_sel_tbutton", 's', GDK_MOD1_MASK},
526         {"show_all_tbutton", '1', GDK_CONTROL_MASK},
527         {"zoom_in_tbutton", '=', GDK_CONTROL_MASK},
528         {"zoom_out_tbutton", '-', GDK_CONTROL_MASK}
529     };
530 
531     accel_group = gtk_accel_group_new();
532     gtk_window_add_accel_group(GTK_WINDOW(mainwindow), accel_group);
533     for (i = 0; i < sizeof(accel_list) / sizeof(accel_list[0]); i++)
534         gtk_widget_add_accelerator(gui_get_widget(builder, accel_list[i].title, S_E_XML),
535         "clicked", accel_group, accel_list[i].key, accel_list[i].mods, 0);
536 
537 #if USE_SNDFILE || AUDIOFILE_VERSION
538     thing = gui_get_widget(builder, "save_wav_tbutton", S_E_XML);
539     list_data_sensitive = g_slist_prepend(list_data_sensitive, thing);
540     gtk_widget_show(thing);
541     g_signal_connect_swapped(thing, "clicked",
542         G_CALLBACK(fileops_open_dialog), savesmp);
543 
544     thing = gui_get_widget(builder, "open_smp_tbutton", S_E_XML);
545     gtk_widget_show(thing);
546     g_signal_connect_swapped(thing, "clicked",
547         G_CALLBACK(fileops_open_dialog), loadsmp);
548 
549     thing = gui_get_widget(builder, "open_smp", S_E_XML);
550     gtk_widget_show(thing);
551     g_signal_connect_swapped(thing, "activate",
552         G_CALLBACK(fileops_open_dialog), loadsmp);
553 
554     thing = gui_get_widget(builder, "save_wav", S_E_XML);
555     gtk_widget_show(thing);
556     g_signal_connect_swapped(thing, "activate",
557         G_CALLBACK(fileops_open_dialog), savesmp);
558 
559     list_data_sensitive = g_slist_prepend(list_data_sensitive, thing);
560     thing = gui_get_widget(builder, "save_reg", S_E_XML);
561     gtk_widget_show(thing);
562     g_signal_connect_swapped(thing, "activate",
563         G_CALLBACK(fileops_open_dialog), savereg);
564 
565     list_data_sensitive = g_slist_prepend(list_data_sensitive, thing);
566     thing = gui_get_widget(builder, "fileop_sep", S_E_XML);
567     gtk_widget_show(thing);
568 #endif
569 
570     thing = gui_get_widget(builder, "select_all_tbutton", S_E_XML);
571     list_data_sensitive = g_slist_prepend(list_data_sensitive, thing);
572     thing = gui_get_widget(builder, "select_none_tbutton", S_E_XML);
573     list_data_sensitive = g_slist_prepend(list_data_sensitive, thing);
574 
575     thing = sample_display_new(TRUE, gui_settings.editor_mode);
576     gtk_box_pack_start(GTK_BOX(box), thing, TRUE, TRUE, 0);
577     gtk_widget_show(thing);
578     g_signal_connect(thing, "loop_changed",
579         G_CALLBACK(sample_editor_display_loop_changed), NULL);
580     g_signal_connect(thing, "selection_changed",
581         G_CALLBACK(sample_editor_display_selection_changed), NULL);
582     g_signal_connect(thing, "motion_notify_event",
583         G_CALLBACK(sample_display_cursor_motion), NULL);
584     gtk_widget_add_events(thing, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
585     g_signal_connect(thing, "enter_notify_event",
586         G_CALLBACK(sample_display_border_cross), GINT_TO_POINTER(TRUE));
587     g_signal_connect(thing, "leave_notify_event",
588         G_CALLBACK(sample_display_border_cross), GINT_TO_POINTER(FALSE));
589     sampledisplay = SAMPLE_DISPLAY(thing);
590     sample_display_enable_zero_line(SAMPLE_DISPLAY(thing), TRUE);
591 
592     sample_editor_hscrollbar = gtk_hscrollbar_new(NULL);
593     adj = gtk_range_get_adjustment(GTK_RANGE(sample_editor_hscrollbar));
594     gtk_widget_show(sample_editor_hscrollbar);
595     gtk_box_pack_start(GTK_BOX(box), sample_editor_hscrollbar, FALSE, TRUE, 0);
596     scrollbar_cb_tag = g_signal_connect_swapped(sample_editor_hscrollbar, "value-changed",
597                                                 G_CALLBACK(sample_editor_hscrollbar_changed), adj);
598     g_signal_connect_swapped(thing, "window_changed",
599                              G_CALLBACK(sample_editor_display_window_changed), adj);
600     g_signal_connect_swapped(thing, "position_changed",
601                              G_CALLBACK(sample_editor_display_position_changed), adj);
602     g_signal_connect_swapped(thing, "scroll-event",
603                              G_CALLBACK(sample_editor_display_scrolled), adj);
604 
605     hbox = gtk_hbox_new(FALSE, 8);
606     list_data_sensitive = g_slist_prepend(list_data_sensitive, hbox);
607     gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 4);
608     gtk_widget_show(hbox);
609 
610     tags[SAMPLE_EDITOR_VOLUME] = gui_put_labelled_spin_button(hbox, _("Volume"), 0, 64,
611         &se_spins[SAMPLE_EDITOR_VOLUME], sample_editor_spin_volume_changed, NULL, TRUE);
612     tags[SAMPLE_EDITOR_PANNING] = gui_put_labelled_spin_button(hbox, _("Panning"), -128, 127,
613         &se_spins[SAMPLE_EDITOR_PANNING], sample_editor_spin_panning_changed, NULL, TRUE);
614     tags[SAMPLE_EDITOR_FINETUNE] = gui_put_labelled_spin_button(hbox, _("Finetune"), -128, 127,
615         &se_spins[SAMPLE_EDITOR_FINETUNE], sample_editor_spin_finetune_changed, NULL, TRUE);
616     tags[SAMPLE_EDITOR_RELNOTE] = gui_put_labelled_spin_button(hbox, _("RelNote"), -128, 127,
617         &se_spins[SAMPLE_EDITOR_RELNOTE], sample_editor_spin_relnote_changed, NULL, TRUE);
618     make_radio_group(resolutionlabels, hbox, resolution_radio, FALSE, FALSE, sample_editor_resolution_changed);
619 
620     thing = gtk_hseparator_new();
621     gtk_widget_show(thing);
622     gtk_box_pack_start(GTK_BOX(box), thing, FALSE, TRUE, 0);
623 
624     hbox = gtk_hbox_new(FALSE, 8);
625     list_data_sensitive = g_slist_prepend(list_data_sensitive, hbox);
626     gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 4);
627     gtk_widget_show(hbox);
628 
629     make_radio_group(looplabels, hbox, loopradio, FALSE, FALSE, sample_editor_loopradio_changed);
630     tag_loopstart = gui_put_labelled_spin_button(hbox, _("Start"), 0, 0, &spin_loopstart,
631         sample_editor_loop_changed, GINT_TO_POINTER(FALSE), TRUE);
632     tag_loopend = gui_put_labelled_spin_button(hbox, _("End"), 0, 0, &spin_loopend,
633         sample_editor_loop_changed, GINT_TO_POINTER(TRUE), TRUE);
634     sample_editor_loopradio_changed(GTK_TOGGLE_BUTTON(loopradio[0]));
635 
636     gtk_builder_connect_signals(builder, NULL);
637     g_object_unref(builder);
638 }
639 
640 void
sample_editor_set_mode(SampleEditorDisplay display,SampleDisplayMode mode)641 sample_editor_set_mode(SampleEditorDisplay display, SampleDisplayMode mode)
642 {
643     SampleDisplay* disp = (display == SAMPLE_EDITOR_DISPLAY_EDITOR) ? sampledisplay : monitorscope;
644 
645     if (disp && IS_SAMPLE_DISPLAY(disp)) {
646         sample_display_set_mode(disp, mode);
647         gtk_widget_queue_draw(GTK_WIDGET(disp));
648     }
649 }
650 
651 static void
sample_editor_blocked_set_loop_spins(int start,int end)652 sample_editor_blocked_set_loop_spins(int start,
653     int end)
654 {
655     gdouble min, max;
656 
657     sample_editor_block_loop_spins(1);
658     gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_loopstart), start);
659     gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_loopend), end);
660     gtk_spin_button_set_range(GTK_SPIN_BUTTON(spin_loopstart), 0, end - 1);
661     gtk_spin_button_get_range(GTK_SPIN_BUTTON(spin_loopend), &min, &max);
662     gtk_spin_button_set_range(GTK_SPIN_BUTTON(spin_loopend), start + 1, max);
663     sample_editor_block_loop_spins(0);
664 }
665 
666 static void
sample_editor_set_sensitive(gboolean sensitive)667 sample_editor_set_sensitive(gboolean sensitive)
668 {
669     GSList *l = list_data_sensitive;
670 
671     for (;l;l = l->next)
672         gtk_widget_set_sensitive(GTK_WIDGET(l->data), sensitive);
673 }
674 
675 static gboolean
sample_editor_update_idle_func(guint * handler)676 sample_editor_update_idle_func(guint *handler)
677 {
678     STSample *sts = current_sample;
679     st_mixer_sample_info *s;
680 
681     gui_block_signals(se_spins, tags, TRUE);
682     gtk_spin_button_set_value(GTK_SPIN_BUTTON(se_spins[SAMPLE_EDITOR_VOLUME]), sts->volume);
683     gtk_spin_button_set_value(GTK_SPIN_BUTTON(se_spins[SAMPLE_EDITOR_PANNING]), sts->panning - 128);
684     gtk_spin_button_set_value(GTK_SPIN_BUTTON(se_spins[SAMPLE_EDITOR_FINETUNE]), sts->finetune);
685     gtk_spin_button_set_value(GTK_SPIN_BUTTON(se_spins[SAMPLE_EDITOR_RELNOTE]), sts->relnote);
686     gui_block_signals(se_spins, tags, FALSE);
687 
688     s = &sts->sample;
689 
690     sample_editor_block_loop_spins(1);
691     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(loopradio[s->looptype]), TRUE);
692     gtk_spin_button_set_range(GTK_SPIN_BUTTON(spin_loopstart), 0, s->length ? s->loopend - 1 : 0);
693     gtk_spin_button_set_range(GTK_SPIN_BUTTON(spin_loopend), s->length ? s->loopstart + 1 : 1, s->length);
694     gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_loopstart), (s->loopstart));
695     gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_loopend), (s->loopend));
696     sample_editor_block_loop_spins(0);
697 
698     if (s->data) {
699         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_radio[sts->treat_as_8bit ? 0 : 1]), TRUE);
700         sample_editor_set_sensitive(TRUE);
701     }
702     sample_editor_update_status();
703 
704     *handler = 0;
705     return FALSE;
706 }
707 
sample_editor_update(void)708 void sample_editor_update(void)
709 {
710     static guint handler = 0;
711 
712     STSample* sts = current_sample;
713 
714     sample_display_set_data(sampledisplay, NULL, ST_MIXER_FORMAT_S16_LE, 0, FALSE);
715 
716     if (!sts || !sts->sample.data)
717         sample_editor_set_sensitive(FALSE);
718 
719     if (!sts) {
720         return;
721     }
722 
723     gui_block_smplname_entry(TRUE); /* To prevent the callback */
724     gtk_entry_set_text(GTK_ENTRY(gui_cursmpl_name), sts->utf_name);
725     gui_block_smplname_entry(FALSE);
726 
727     if (sts->sample.data) {
728         sample_display_set_data(sampledisplay, sts->sample.data, ST_MIXER_FORMAT_S16_LE, sts->sample.length, FALSE);
729 
730         if (sts->sample.looptype != ST_MIXER_SAMPLE_LOOPTYPE_NONE)
731             sample_editor_blocked_set_display_loop(sts->sample.loopstart, sts->sample.loopend);
732     }
733 
734     if (!handler)
735         handler = g_idle_add((GSourceFunc)sample_editor_update_idle_func, &handler);
736     g_assert(handler != 0);
737 }
738 
739 void
sample_editor_remove_clicked(void)740 sample_editor_remove_clicked(void)
741 {
742     sample_editor_copy_cut_common(FALSE, TRUE);
743 }
744 
745 void
sample_editor_select_none_clicked(void)746 sample_editor_select_none_clicked(void)
747 {
748     sample_display_set_selection(sampledisplay, -1, 1);
749 }
750 
751 void
sample_editor_select_all_clicked(void)752 sample_editor_select_all_clicked(void)
753 {
754     g_return_if_fail(current_sample != NULL);
755 
756     sample_display_set_selection(sampledisplay,
757         0, current_sample->sample.length);
758 }
759 
760 gboolean
sample_editor_handle_keys(int shift,int ctrl,int alt,guint32 keyval,gboolean pressed)761 sample_editor_handle_keys(int shift,
762     int ctrl,
763     int alt,
764     guint32 keyval,
765     gboolean pressed)
766 {
767     gboolean is_note = FALSE;
768     int s = sampledisplay->sel_start, e = sampledisplay->sel_end;
769     int modifiers = ENCODE_MODIFIERS(shift, ctrl, alt);
770 
771     if (s == -1) {
772         s = 0;
773         e = current_sample->sample.length;
774     }
775 
776     if (pressed)
777         switch (keyval) {
778         case GDK_KEY_Delete:
779             if (!(shift || alt || ctrl)) {
780                 sample_editor_remove_clicked();
781                 return TRUE;
782             }
783             break;
784         case 'a':
785             if (ctrl && !alt) {
786                 sample_editor_select_all_clicked();
787                 return TRUE;
788             }
789             break;
790         case 'A':
791             if (ctrl && !alt) {
792                 sample_editor_select_none_clicked();
793                 return TRUE;
794             }
795             break;
796         default:
797             break;
798         }
799 
800     gui_play_note_no_repeat(keyval, modifiers, pressed,
801         current_sample, s, e - s, tracker->cursor_ch, TRUE, &is_note, FALSE);
802     return is_note;
803 }
804 
sample_editor_set_sample(STSample * s)805 void sample_editor_set_sample(STSample* s)
806 {
807     current_sample = s;
808     sample_editor_update();
809 }
810 
811 static void
sample_editor_update_mixer_position(double songtime)812 sample_editor_update_mixer_position(double songtime)
813 {
814     audio_mixer_position* p;
815     int i;
816 
817     if (songtime >= 0.0 && current_sample && (p = time_buffer_get(audio_mixer_position_tb, songtime))) {
818         for (i = 0; i < ARRAY_SIZE(p->dump); i++) {
819             if (p->dump[i].current_sample == &current_sample->sample) {
820                 sample_display_set_mixer_position(sampledisplay, p->dump[i].current_position);
821                 g_free(p);
822                 return;
823             }
824         }
825         g_free(p);
826     }
827 
828     sample_display_set_mixer_position(sampledisplay, -1);
829 }
830 
831 static gint
sample_editor_update_timeout(gpointer data)832 sample_editor_update_timeout(gpointer data)
833 {
834     double display_songtime;
835 
836     if (current_driver == NULL)
837         return FALSE;
838 
839     display_songtime = current_driver->get_play_time(current_driver_object);
840     sample_editor_update_mixer_position(display_songtime);
841 
842     return TRUE;
843 }
844 
sample_editor_start_updating(void)845 void sample_editor_start_updating(void)
846 {
847     if (gtktimer != -1)
848         return;
849 
850     gtktimer = g_timeout_add(1000 / gui_settings.scopes_update_freq, sample_editor_update_timeout, NULL);
851 }
852 
sample_editor_stop_updating(void)853 void sample_editor_stop_updating(void)
854 {
855     if (gtktimer == -1)
856         return;
857 
858     g_source_remove(gtktimer);
859     gtktimer = -1;
860     sample_editor_update_mixer_position(-1.0);
861 }
862 
863 static void
sample_editor_spin_volume_changed(GtkSpinButton * spin)864 sample_editor_spin_volume_changed(GtkSpinButton* spin)
865 {
866     g_return_if_fail(current_sample != NULL);
867 
868     history_log_spin_button(spin, _("Sample volume setting"), HISTORY_FLAG_LOG_ALL,
869         current_sample->volume);
870     current_sample->volume = gtk_spin_button_get_value_as_int(spin);
871 }
872 
873 static void
sample_editor_spin_panning_changed(GtkSpinButton * spin)874 sample_editor_spin_panning_changed(GtkSpinButton* spin)
875 {
876     g_return_if_fail(current_sample != NULL);
877 
878     if (current_sample->sample.data) {
879         history_log_spin_button(spin, _("Sample panning setting"), HISTORY_FLAG_LOG_ALL,
880             current_sample->panning);
881         current_sample->panning = gtk_spin_button_get_value_as_int(spin) + 128;
882     }
883 }
884 
885 static void
sample_editor_spin_finetune_changed(GtkSpinButton * spin)886 sample_editor_spin_finetune_changed(GtkSpinButton* spin)
887 {
888     if (!current_sample)
889         return;
890 
891     if (current_sample->sample.data) {
892         history_log_spin_button(spin, _("Sample finetune setting"), HISTORY_FLAG_LOG_ALL,
893             current_sample->finetune);
894         current_sample->finetune = gtk_spin_button_get_value_as_int(spin);
895     }
896 }
897 
898 static void
sample_editor_spin_relnote_changed(GtkSpinButton * spin)899 sample_editor_spin_relnote_changed(GtkSpinButton* spin)
900 {
901     if (!current_sample)
902         return;
903 
904     history_log_spin_button(spin, _("Sample relnote setting"), HISTORY_FLAG_LOG_ALL,
905         current_sample->relnote);
906     current_sample->relnote = gtk_spin_button_get_value_as_int(spin);
907 }
908 
909 struct LoopArg {
910     gint start, end, type;
911 };
912 
913 static void
sample_loop_undo(const gint ins,const gint smp,const gboolean redo,gpointer arg,gpointer data)914 sample_loop_undo(const gint ins, const gint smp, const gboolean redo,
915     gpointer arg, gpointer data)
916 {
917     struct LoopArg* la = arg;
918     STSample* s = data;
919     gint tmp_val;
920 
921     g_assert(s != NULL);
922 
923     sample_editor_lock_sample();
924     tmp_val = s->sample.loopstart;
925     s->sample.loopstart = la->start;
926     la->start = tmp_val;
927     tmp_val = s->sample.loopend;
928     s->sample.loopend = la->end;
929     la->end = tmp_val;
930     tmp_val = s->sample.looptype;
931     s->sample.looptype = la->type;
932     la->type = tmp_val;
933     sample_editor_unlock_sample();
934 
935     sample_editor_update();
936 }
937 
938 void
sample_editor_selection_to_loop_clicked(void)939 sample_editor_selection_to_loop_clicked(void)
940 {
941     int s = sampledisplay->sel_start, e = sampledisplay->sel_end;
942     struct LoopArg* la;
943 
944     g_return_if_fail(current_sample != NULL);
945     g_return_if_fail(current_sample->sample.data != NULL);
946 
947     if (s == -1) {
948         return;
949     }
950 
951     la = g_new(struct LoopArg, 1);
952     la->start = current_sample->sample.loopstart;
953     la->end = current_sample->sample.loopend;
954     la->type = current_sample->sample.looptype;
955     history_log_action(HISTORY_ACTION_POINTER, _("Sample loop setting"), HISTORY_FLAG_LOG_ALL,
956         sample_loop_undo, current_sample, sizeof(struct LoopArg), la);
957 
958     sample_editor_lock_sample();
959     current_sample->sample.loopend = e;
960     current_sample->sample.loopstart = s;
961     if (current_sample->sample.looptype == ST_MIXER_SAMPLE_LOOPTYPE_NONE) {
962         current_sample->sample.looptype = ST_MIXER_SAMPLE_LOOPTYPE_AMIGA;
963         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(loopradio[1]), TRUE);
964     }
965     sample_editor_unlock_sample();
966 
967     sample_editor_blocked_set_loop_spins(s, e);
968     sample_editor_blocked_set_display_loop(s, e);
969 }
970 
971 static void
sample_editor_display_loop_changed(SampleDisplay * sample_display,int start,int end)972 sample_editor_display_loop_changed(SampleDisplay* sample_display,
973     int start,
974     int end)
975 {
976     g_return_if_fail(current_sample != NULL);
977     g_return_if_fail(current_sample->sample.data != NULL);
978     g_return_if_fail(current_sample->sample.looptype != ST_MIXER_SAMPLE_LOOPTYPE_NONE);
979     g_return_if_fail(start < end);
980 
981     if (start != current_sample->sample.loopstart)
982         gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_loopstart), start);
983     if (end != current_sample->sample.loopend)
984         gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_loopend), end);
985 }
986 
987 static void
sample_editor_display_selection_changed(SampleDisplay * sample_display,int start,int end)988 sample_editor_display_selection_changed(SampleDisplay* sample_display,
989     int start,
990     int end)
991 {
992     g_return_if_fail(current_sample != NULL);
993     g_return_if_fail(current_sample->sample.data != NULL);
994     g_return_if_fail(start < end);
995 
996     sample_editor_update_status();
997 }
998 
999 static void
sample_editor_display_window_changed(GtkAdjustment * adj,int start,int end,SampleDisplay * s)1000 sample_editor_display_window_changed(GtkAdjustment *adj,
1001     int start,
1002     int end,
1003     SampleDisplay* s)
1004 {
1005     const gint w = end - start;
1006     const gdouble step = (s->width == 0 || s->width >= w ) ? 1.0 : (gdouble)w / (gdouble)s->width;
1007 
1008     if (current_sample == NULL)
1009         return;
1010 
1011     g_signal_handler_block(G_OBJECT(sample_editor_hscrollbar), scrollbar_cb_tag);
1012     gtk_adjustment_configure(adj, start, 0, current_sample->sample.length,
1013         step, w > 2 ? w - 2 : 1, w);
1014     g_signal_handler_unblock(G_OBJECT(sample_editor_hscrollbar), scrollbar_cb_tag);
1015 }
1016 
1017 static void
sample_editor_display_position_changed(GtkAdjustment * adj,int pos)1018 sample_editor_display_position_changed(GtkAdjustment *adj,
1019    int pos)
1020 {
1021     if (current_sample == NULL)
1022         return;
1023 
1024     g_signal_handler_block(G_OBJECT(sample_editor_hscrollbar), scrollbar_cb_tag);
1025     gtk_adjustment_set_value(adj, pos);
1026     g_signal_handler_unblock(G_OBJECT(sample_editor_hscrollbar), scrollbar_cb_tag);
1027 }
1028 
1029 static void
sample_editor_loopradio_changed(GtkToggleButton * tb)1030 sample_editor_loopradio_changed(GtkToggleButton* tb)
1031 {
1032     gint n;
1033 
1034     if (!gtk_toggle_button_get_active(tb))
1035         return;
1036 
1037     n = find_current_toggle(loopradio, 3);
1038     gtk_widget_set_sensitive(spin_loopstart, n != 0);
1039     gtk_widget_set_sensitive(spin_loopend, n != 0);
1040 
1041     if (current_sample != NULL) {
1042         if (current_sample->sample.looptype == n)
1043             return;
1044 
1045         history_log_radio_group(loopradio, _("Sample loop type setting"),
1046             HISTORY_FLAG_LOG_ALL, current_sample->sample.looptype, 3);
1047         sample_editor_lock_sample();
1048         current_sample->sample.looptype = n;
1049         sample_editor_unlock_sample();
1050 
1051         if (n != ST_MIXER_SAMPLE_LOOPTYPE_NONE) {
1052             sample_editor_blocked_set_display_loop(current_sample->sample.loopstart, current_sample->sample.loopend);
1053         } else {
1054             sample_editor_blocked_set_display_loop(-1, 1);
1055         }
1056     }
1057 }
1058 
1059 struct SampleBackup {
1060     STSample sample;
1061     gint16 data[1];
1062 };
1063 
1064 static void
sample_total_undo(const gint ins,const gint smp,const gboolean redo,gpointer arg,gpointer data)1065 sample_total_undo(const gint ins, const gint smp, const gboolean redo,
1066     gpointer arg, gpointer data)
1067 {
1068     STSample *sample = data;
1069     struct SampleBackup *sb = arg;
1070     const gsize data_length = sample->sample.length * sizeof(sample->sample.data[0]);
1071     gint16* tmp_data = NULL;
1072     STSample tmp_smp;
1073     GMutex tmp_lock;
1074 
1075     if (data_length) {
1076         tmp_data = g_malloc(data_length);
1077         if (!tmp_data) {
1078             gui_oom_error();
1079             return;
1080         }
1081         memcpy(tmp_data, sample->sample.data, data_length);
1082     }
1083     tmp_smp = *sample;
1084 
1085     g_mutex_lock(&sample->sample.lock);
1086     tmp_lock = sample->sample.lock;
1087     if (sample->sample.length && sample->sample.data)
1088         g_free(sample->sample.data);
1089     *sample = sb->sample;
1090     if (sample->sample.length) {
1091         sample->sample.data = g_new(gint16, sample->sample.length);
1092         memcpy(sample->sample.data, sb->data, sample->sample.length * sizeof(sb->data[0]));
1093     } else
1094         sample->sample.data = NULL;
1095     sample->sample.lock = tmp_lock;
1096     g_mutex_unlock(&sample->sample.lock);
1097 
1098     sb->sample = tmp_smp;
1099     if (tmp_data) {
1100         memcpy(sb->data, tmp_data, sb->sample.sample.length * sizeof(tmp_data[0]));
1101         g_free(tmp_data);
1102     }
1103 
1104     if (sample == current_sample)
1105         sample_editor_update();
1106     modinfo_update_instrument(ins - 1);
1107 }
1108 
1109 gboolean
sample_editor_check_and_log_sample(STSample * sample,const gchar * title,const gint flags,const gsize data_length)1110 sample_editor_check_and_log_sample(STSample* sample,
1111     const gchar* title,
1112     const gint flags,
1113     const gsize data_length)
1114 {
1115     const gsize arg_size = ((data_length ? data_length : sample->sample.length) - 1)
1116         * sizeof(sample->sample.data[0]) + sizeof(struct SampleBackup);
1117 
1118     if (history_check_size(arg_size)) {
1119         /* Undo is possible */
1120         struct SampleBackup* arg = g_malloc(arg_size);
1121 
1122         if (!arg) {
1123             gui_oom_error();
1124             return FALSE;
1125         }
1126         arg->sample = *sample;
1127         memcpy(arg->data, sample->sample.data,
1128             sample->sample.length * sizeof(sample->sample.data[0]));
1129         history_log_action(HISTORY_ACTION_POINTER, _(title), flags,
1130             sample_total_undo, sample, arg_size, arg);
1131     } else if (!history_query_oversized(mainwindow))
1132         /* User rejected to continue without undo */
1133         return FALSE;
1134 
1135     return TRUE;
1136 }
1137 
1138 struct RangeBackup {
1139     gsize start, end;
1140     gint16 data[1];
1141 };
1142 
1143 static void
sample_range_undo(const gint ins,const gint smp,const gboolean redo,gpointer arg,gpointer data)1144 sample_range_undo(const gint ins, const gint smp, const gboolean redo,
1145     gpointer arg, gpointer data)
1146 {
1147     STSample *sample = data;
1148     struct RangeBackup *rb = arg;
1149     const gsize data_length = (rb->end - rb->start) * sizeof(sample->sample.data[0]);
1150     gint16* tmp_data = g_malloc(data_length);
1151 
1152     if (!tmp_data) {
1153         gui_oom_error();
1154         return;
1155     }
1156     memcpy(tmp_data, &sample->sample.data[rb->start], data_length);
1157     g_mutex_lock(&sample->sample.lock);
1158     memcpy(&sample->sample.data[rb->start], rb->data, data_length);
1159     g_mutex_unlock(&sample->sample.lock);
1160     memcpy(rb->data, tmp_data, data_length);
1161 
1162     g_free(tmp_data);
1163     if (sample == current_sample)
1164         sample_editor_update();
1165 }
1166 
1167 static gboolean
sample_editor_check_and_log_range(STSample * sample,const gchar * title,const gint flags,const gsize start,const gsize end)1168 sample_editor_check_and_log_range(STSample* sample,
1169     const gchar* title,
1170     const gint flags,
1171     const gsize start,
1172     const gsize end)
1173 {
1174     const gsize arg_size = (end - start - 1) * sizeof(sample->sample.data[0])
1175         + sizeof(struct RangeBackup);
1176 
1177     g_assert(end > start);
1178 
1179     if (history_check_size(arg_size)) {
1180         /* Undo is possible */
1181         struct RangeBackup* arg = g_malloc(arg_size);
1182 
1183         if (!arg) {
1184             gui_oom_error();
1185             return FALSE;
1186         }
1187         arg->start = start;
1188         arg->end = end;
1189         memcpy(arg->data, &sample->sample.data[start],
1190             (end - start) * sizeof(sample->sample.data[0]));
1191         history_log_action(HISTORY_ACTION_POINTER, _(title), flags,
1192             sample_range_undo, sample, arg_size, arg);
1193     } else if (!history_query_oversized(mainwindow))
1194         /* User rejected to continue without undo */
1195         return FALSE;
1196 
1197     return TRUE;
1198 }
1199 
1200 static void
sample_editor_do_clear(const gchar * title)1201 sample_editor_do_clear(const gchar* title)
1202 {
1203     STInstrument* instr;
1204     gint nsam;
1205 
1206     sample_editor_lock_sample();
1207 
1208     instr = instrument_editor_get_instrument();
1209     nsam = st_instrument_num_samples(instr);
1210     if (!nsam) /* All samples are empty, nothing to do */
1211         return;
1212 
1213     if (nsam > 1) {
1214         if (!sample_editor_check_and_log_sample(current_sample,
1215             title, HISTORY_FLAG_LOG_ALL, 0))
1216             return;
1217     } else {
1218         if (!instrument_editor_check_and_log_instrument(instr,
1219             title, HISTORY_FLAG_LOG_ALL, 0))
1220             return;
1221     }
1222     st_clean_sample_full(current_sample, NULL, NULL, FALSE);
1223 
1224     if (nsam == 1) /* Was 1 _before_ cleaning */
1225         st_clean_instrument_full(instr, NULL, FALSE);
1226 
1227     instrument_editor_update(TRUE);
1228     sample_editor_update();
1229 
1230     sample_editor_unlock_sample();
1231 }
1232 
1233 void
sample_editor_clear_clicked(void)1234 sample_editor_clear_clicked(void)
1235 {
1236     sample_editor_do_clear(N_("Sample cleaning"));
1237 }
1238 
1239 void
sample_editor_crop_clicked(void)1240 sample_editor_crop_clicked(void)
1241 {
1242     gint l, start = sampledisplay->sel_start, end = sampledisplay->sel_end;
1243 
1244     if (current_sample == NULL || start == -1)
1245         return;
1246 
1247     if (!sample_editor_check_and_log_sample(current_sample,
1248         N_("Sample cropping"), HISTORY_FLAG_LOG_ALL, 0))
1249         return;
1250     l = current_sample->sample.length;
1251 
1252     sample_editor_lock_sample();
1253     sample_editor_delete(current_sample, 0, start);
1254     sample_editor_delete(current_sample, end - start, l - start);
1255     sample_editor_unlock_sample();
1256 
1257     sample_editor_update();
1258 }
1259 
1260 void
sample_editor_show_all_clicked(void)1261 sample_editor_show_all_clicked(void)
1262 {
1263     if (current_sample == NULL || current_sample->sample.data == NULL)
1264         return;
1265     sample_display_set_window(sampledisplay, 0, current_sample->sample.length);
1266 }
1267 
1268 void
sample_editor_zoom_in_clicked(void)1269 sample_editor_zoom_in_clicked(void)
1270 {
1271     int ns = sampledisplay->win_start,
1272         ne = sampledisplay->win_start + sampledisplay->win_length;
1273     int l;
1274 
1275     if (current_sample == NULL || current_sample->sample.data == NULL)
1276         return;
1277 
1278     l = sampledisplay->win_length / 4;
1279 
1280     ns += l;
1281     ne -= l;
1282 
1283     if (ne <= ns)
1284         ne = ns + 1;
1285 
1286     sample_display_set_window(sampledisplay, ns, ne);
1287 }
1288 
1289 void
sample_editor_zoom_out_clicked(void)1290 sample_editor_zoom_out_clicked(void)
1291 {
1292     int ns = sampledisplay->win_start,
1293         ne = sampledisplay->win_start + sampledisplay->win_length;
1294     int l;
1295 
1296     if (current_sample == NULL || current_sample->sample.data == NULL)
1297         return;
1298 
1299     l = sampledisplay->win_length / 2;
1300 
1301     if (ns > l)
1302         ns -= l;
1303     else
1304         ns = 0;
1305 
1306     if (ne <= current_sample->sample.length - l)
1307         ne += l;
1308     else
1309         ne = current_sample->sample.length;
1310 
1311     sample_display_set_window(sampledisplay, ns, ne);
1312 }
1313 
1314 void
sample_editor_zoom_to_selection_clicked(void)1315 sample_editor_zoom_to_selection_clicked(void)
1316 {
1317     gint ss, se, sl;
1318 
1319     if (current_sample == NULL || current_sample->sample.data == NULL || sampledisplay->sel_start == -1)
1320         return;
1321 
1322     sl = current_sample->sample.length;
1323     if (sl <= 2)
1324         return;
1325 
1326     ss = sampledisplay->sel_start;
1327     se = sampledisplay->sel_end;
1328     /* There's no sence in zooming to one sample, but this causes some problems.
1329 	   In order to avoid this we restrict the minimal zoom size to 2 samples */
1330     if (se <= ss + 1)
1331         se = ss + 2;
1332     if (se >= sl) {
1333         ss -= (se - sl);
1334         se = sl;
1335     }
1336 
1337     sample_display_set_window(sampledisplay, ss, se);
1338 }
1339 
1340 static void
copy_smp_to_tmp(STSample * smp)1341 copy_smp_to_tmp(STSample* smp)
1342 {
1343     if (!tmp_sample)
1344         tmp_sample = g_new0(STSample, 1);
1345     if (!tmp_sample) {
1346         gui_oom_error();
1347         return;
1348     }
1349     st_copy_sample(smp, tmp_sample);
1350 }
1351 
1352 void
sample_editor_xcopy_samples(STSample * src_smp,STSample * dest_smp,const gboolean xchg)1353 sample_editor_xcopy_samples(STSample* src_smp,
1354     STSample* dest_smp,
1355     const gboolean xchg)
1356 {
1357     if (xchg) {
1358         /* We need a place to store one of the samples during the exchange */
1359         copy_smp_to_tmp(dest_smp);
1360     }
1361     g_mutex_lock(&dest_smp->sample.lock);
1362     st_copy_sample(src_smp, dest_smp);
1363     g_mutex_unlock(&dest_smp->sample.lock);
1364     if (xchg) {
1365         g_mutex_lock(&src_smp->sample.lock);
1366         st_copy_sample(tmp_sample, src_smp);
1367         g_mutex_unlock(&src_smp->sample.lock);
1368     }
1369 }
1370 
sample_editor_copy_cut_common(gboolean copy,gboolean spliceout)1371 void sample_editor_copy_cut_common(gboolean copy,
1372     gboolean spliceout)
1373 {
1374     int cutlen, newlen;
1375     gint16* newsample;
1376     STSample* oldsample = current_sample;
1377     int ss = sampledisplay->sel_start, se;
1378 
1379     if (oldsample == NULL || oldsample->sample.length == 0)
1380         return;
1381 
1382     se = sampledisplay->sel_end;
1383 
1384     cutlen = se - ss;
1385     newlen = oldsample->sample.length - cutlen;
1386 
1387     if (copy) {
1388         if (ss == -1) { /* Whole sample */
1389             copy_smp_to_tmp(oldsample);
1390             copy_whole_sample = TRUE;
1391             newlen = 0; /* If we will cut sample, cut it all */
1392         } else {
1393             if (copybuffer) {
1394                 free(copybuffer);
1395                 copybuffer = NULL;
1396             }
1397             copybufferlen = cutlen;
1398             copybuffer = malloc(copybufferlen * 2);
1399             if (!copybuffer)
1400                 gui_oom_error();
1401             else {
1402                 memcpy(copybuffer,
1403                     oldsample->sample.data + ss,
1404                     cutlen * 2);
1405             }
1406             memcpy(&copybuffer_sampleinfo, oldsample, sizeof(STSample));
1407             copy_whole_sample = FALSE;
1408         }
1409     }
1410 
1411     if (!spliceout || ss == -1)
1412         return;
1413 
1414     if (newlen == 0) {
1415         sample_editor_do_clear(N_("Sample cut"));
1416         return;
1417     }
1418 
1419     if (!sample_editor_check_and_log_sample(current_sample,
1420         N_("Sample cut"), HISTORY_FLAG_LOG_ALL, 0))
1421         return;
1422 
1423     newsample = malloc(newlen * 2);
1424     if (!newsample)
1425         return;
1426 
1427     sample_editor_lock_sample();
1428 
1429     memcpy(newsample,
1430         oldsample->sample.data,
1431         ss * 2);
1432     memcpy(newsample + ss,
1433         oldsample->sample.data + se,
1434         (oldsample->sample.length - se) * 2);
1435 
1436     free(oldsample->sample.data);
1437 
1438     oldsample->sample.data = newsample;
1439     oldsample->sample.length = newlen;
1440 
1441     /* Move loop start and end along with splice */
1442     if (oldsample->sample.loopstart > ss && oldsample->sample.loopend < se) {
1443         /* loop was wholly within selection -- remove it */
1444         oldsample->sample.looptype = ST_MIXER_SAMPLE_LOOPTYPE_NONE;
1445         oldsample->sample.loopstart = 0;
1446         oldsample->sample.loopend = 1;
1447     } else {
1448         if (oldsample->sample.loopstart > se) {
1449             /* loopstart was after selection */
1450             oldsample->sample.loopstart -= (se - ss);
1451         } else if (oldsample->sample.loopstart > ss) {
1452             /* loopstart was within selection */
1453             oldsample->sample.loopstart = ss;
1454         }
1455 
1456         if (oldsample->sample.loopend > se) {
1457             /* loopend was after selection */
1458             oldsample->sample.loopend -= (se - ss);
1459         } else if (oldsample->sample.loopend > ss) {
1460             /* loopend was within selection */
1461             oldsample->sample.loopend = ss;
1462         }
1463     }
1464 
1465     st_sample_fix_loop(oldsample);
1466     sample_editor_unlock_sample();
1467     sample_editor_set_sample(oldsample);
1468 }
1469 
1470 void
sample_editor_cut_clicked(void)1471 sample_editor_cut_clicked(void)
1472 {
1473     sample_editor_copy_cut_common(TRUE, TRUE);
1474 }
1475 
1476 void
sample_editor_copy_clicked(void)1477 sample_editor_copy_clicked(void)
1478 {
1479     sample_editor_copy_cut_common(TRUE, FALSE);
1480 }
1481 
1482 static void
sample_editor_init_sample_full(STSample * sample,const char * samplename)1483 sample_editor_init_sample_full(STSample* sample, const char* samplename)
1484 {
1485     STInstrument* instr;
1486 
1487     instr = instrument_editor_get_instrument();
1488     if (st_instrument_num_samples(instr) == 0) {
1489         st_clean_instrument(instr, samplename);
1490         memset(instr->samplemap, gui_get_current_sample(), sizeof(instr->samplemap));
1491         if (samplename)
1492             st_set_sample_name(sample, samplename);
1493     } else
1494         st_clean_sample(sample, samplename, NULL);
1495 
1496     sample->volume = 64;
1497     sample->finetune = 0;
1498     sample->panning = 128;
1499     sample->relnote = 0;
1500 }
1501 
1502 static inline void
sample_editor_init_sample(const char * samplename)1503 sample_editor_init_sample(const char* samplename)
1504 {
1505     sample_editor_init_sample_full(current_sample, samplename);
1506 }
1507 
sample_editor_paste_clicked(void)1508 void sample_editor_paste_clicked(void)
1509 {
1510     gint16* newsample;
1511     STSample* oldsample = current_sample;
1512     gint ss = sampledisplay->sel_start, newlen;
1513     gboolean update_ie = FALSE;
1514 
1515     if (oldsample == NULL)
1516         return;
1517 
1518     if (copy_whole_sample) {
1519         if (!tmp_sample)
1520             return;
1521 
1522         if (!oldsample->sample.data) {
1523             STInstrument* curins = instrument_editor_get_instrument();
1524 
1525             if (!st_instrument_num_samples(curins)) {
1526                 /* pasting into empty instrument; backing up the whole instrument */
1527                 const gsize i_size = sizeof(STInstrument) + copybufferlen * sizeof(oldsample->sample.data[0]);
1528 
1529                 if (!instrument_editor_check_and_log_instrument(curins, N_("Sample paste"),
1530                     HISTORY_FLAG_LOG_ALL, i_size))
1531                     return;
1532                 sample_editor_init_sample(NULL);
1533             } else {
1534                 if (!sample_editor_check_and_log_sample(current_sample,
1535                     N_("Sample paste"), HISTORY_FLAG_LOG_ALL, tmp_sample->sample.length))
1536                     return;
1537             }
1538             update_ie = TRUE;
1539         } else {
1540             if (!sample_editor_check_and_log_sample(current_sample,
1541                 N_("Sample paste"), HISTORY_FLAG_LOG_ALL,
1542                 MAX(tmp_sample->sample.length, oldsample->sample.length)))
1543                 return;
1544         }
1545         sample_editor_lock_sample();
1546         st_copy_sample(tmp_sample, oldsample);
1547     } else {
1548         if ((oldsample->sample.data && ss == -1) || copybuffer == NULL)
1549             return;
1550         newlen = oldsample->sample.length + copybufferlen;
1551 
1552         if (!oldsample->sample.data) {
1553             STInstrument* curins = instrument_editor_get_instrument();
1554 
1555             if (!st_instrument_num_samples(curins)) {
1556                 /* pasting into empty instrument; backing up the whole instrument */
1557                 const gsize i_size = sizeof(STInstrument) + copybufferlen * sizeof(oldsample->sample.data[0]);
1558 
1559                 if (!instrument_editor_check_and_log_instrument(curins, N_("Sample paste"),
1560                     HISTORY_FLAG_LOG_ALL, i_size))
1561                     return;
1562             } else {
1563                 if (!sample_editor_check_and_log_sample(current_sample,
1564                     N_("Sample paste"), HISTORY_FLAG_LOG_ALL, newlen))
1565                     return;
1566             }
1567             /* pasting into empty sample */
1568             sample_editor_lock_sample();
1569             sample_editor_init_sample(_("<just pasted>")); /* Use only charachers from FT2 codeset in the translation! */
1570             oldsample->treat_as_8bit = copybuffer_sampleinfo.treat_as_8bit;
1571             oldsample->volume = copybuffer_sampleinfo.volume;
1572             oldsample->finetune = copybuffer_sampleinfo.finetune;
1573             oldsample->panning = copybuffer_sampleinfo.panning;
1574             oldsample->relnote = copybuffer_sampleinfo.relnote;
1575             sample_editor_unlock_sample();
1576             ss = 0;
1577             update_ie = TRUE;
1578         } else {
1579             if (!sample_editor_check_and_log_sample(current_sample,
1580                 N_("Sample paste"), HISTORY_FLAG_LOG_ALL, newlen))
1581                 return;
1582         }
1583 
1584         newsample = malloc(newlen * 2);
1585         if (!newsample)
1586             return;
1587 
1588         sample_editor_lock_sample();
1589 
1590         memcpy(newsample,
1591             oldsample->sample.data,
1592             ss * 2);
1593         memcpy(newsample + ss, copybuffer, copybufferlen);
1594         memcpy(newsample + (ss + copybufferlen),
1595             oldsample->sample.data + ss,
1596             (oldsample->sample.length - ss) * 2);
1597 
1598         free(oldsample->sample.data);
1599 
1600         oldsample->sample.data = newsample;
1601         oldsample->sample.length = newlen;
1602         if (oldsample->sample.loopstart >= ss)
1603             oldsample->sample.loopstart += copybufferlen;
1604         if (oldsample->sample.loopend >= ss)
1605             oldsample->sample.loopend += copybufferlen;
1606     }
1607 
1608     sample_editor_unlock_sample();
1609     sample_editor_update();
1610     if (update_ie)
1611         instrument_editor_update(TRUE);
1612 }
1613 
1614 void
sample_editor_reverse_clicked(void)1615 sample_editor_reverse_clicked(void)
1616 {
1617     int ss = sampledisplay->sel_start, se = sampledisplay->sel_end;
1618     int i;
1619     gint16 *p, *q;
1620     gboolean set_selection = TRUE;
1621 
1622     if (!current_sample) {
1623         return;
1624     }
1625     if (ss == -1) {
1626         ss = 0;
1627         se = current_sample->sample.length;
1628         set_selection = FALSE;
1629     }
1630 
1631     if (!sample_editor_check_and_log_range(current_sample,
1632         N_("Sample reversing"), HISTORY_FLAG_LOG_ALL, ss, se))
1633         return;
1634 
1635     sample_editor_lock_sample();
1636 
1637     p = q = current_sample->sample.data;
1638     p += ss;
1639     q += se;
1640 
1641     for (i = 0; i < (se - ss) / 2; i++) {
1642         gint16 t = *p;
1643         *p++ = *--q;
1644         *q = t;
1645     }
1646 
1647     sample_editor_unlock_sample();
1648     sample_editor_update();
1649     if (set_selection)
1650         sample_display_set_selection(sampledisplay, ss, se);
1651 }
1652 
1653 static void
sample_editor_open_stereo_dialog(GtkWidget ** window,GtkWidget ** buttons,const gchar * text,const gchar * title)1654 sample_editor_open_stereo_dialog(GtkWidget** window, GtkWidget** buttons, const gchar* text,
1655     const gchar* title)
1656 {
1657     static const gchar* labels[] = { N_("Mix"), N_("Left"), N_("Right"), N_("2 samples") };
1658 
1659     if (!*window) {
1660         GtkWidget *thing, *box1;
1661 
1662         *window = gtk_dialog_new_with_buttons(_(title), GTK_WINDOW(mainwindow), GTK_DIALOG_MODAL,
1663             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1664             GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1665         gui_dialog_adjust(*window, 2);
1666         box1 = gtk_dialog_get_content_area(GTK_DIALOG(*window));
1667         gtk_box_set_spacing(GTK_BOX(box1), 2);
1668 
1669         thing = gtk_label_new(text);
1670         gtk_label_set_justify(GTK_LABEL(thing), GTK_JUSTIFY_CENTER);
1671         gtk_box_pack_start(GTK_BOX(box1), thing, FALSE, TRUE, 0);
1672         gtk_widget_show(thing);
1673 
1674         make_radio_group(labels, box1, buttons, FALSE, FALSE, NULL);
1675         gtk_widget_set_tooltip_text(buttons[3], _("Put left and right channels into the current sample and the next one"));
1676         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(buttons[0]), TRUE);
1677 
1678         thing = gtk_hseparator_new();
1679         gtk_box_pack_start(GTK_BOX(box1), thing, FALSE, TRUE, 0);
1680         gtk_widget_show(thing);
1681     } else
1682         gtk_window_present(GTK_WINDOW(*window));
1683 }
1684 
1685 static gboolean
check_and_log_smp_ins(const gchar * title,const gint mode,STSample * cs,STSample * ns,const gsize n_sam)1686 check_and_log_smp_ins(const gchar* title,
1687     const gint mode,
1688     STSample* cs,
1689     STSample* ns,
1690     const gsize n_sam)
1691 {
1692     STInstrument* curins = instrument_editor_get_instrument();
1693 
1694     if (st_instrument_num_samples(curins) && mode != MODE_STEREO_2) {
1695         /* Only one sample is affected */
1696         if (!sample_editor_check_and_log_sample(cs, title,
1697             HISTORY_FLAG_LOG_SMP | HISTORY_FLAG_LOG_INS | HISTORY_SET_PAGE(NOTEBOOK_PAGE_SAMPLE_EDITOR),
1698             MAX(cs->sample.length, n_sam)))
1699             return FALSE;
1700     } else {
1701         /* We either load a sample to an empty instrument or overwrite two samples.
1702            The whole instrument is to be backed up */
1703         const gsize isize1 = st_get_instrument_size(curins);
1704         const gsize isize2 = mode == MODE_STEREO_2 ? isize1 + sizeof(cs->sample.data[0]) *
1705             (2 * n_sam - cs->sample.length - ns->sample.length)
1706             : sizeof(STInstrument) + sizeof(cs->sample.data[0]) * n_sam;
1707         if (!instrument_editor_check_and_log_instrument(curins, title,
1708             HISTORY_FLAG_LOG_SMP | HISTORY_FLAG_LOG_INS |
1709             HISTORY_SET_PAGE(NOTEBOOK_PAGE_SAMPLE_EDITOR), MAX(isize1, isize2)))
1710             return FALSE;
1711     }
1712     return TRUE;
1713 }
1714 
1715 #if USE_SNDFILE || AUDIOFILE_VERSION
1716 
1717 static gboolean
sample_editor_load_wav_main(const int mode,FILE * f,struct wl * wavload)1718 sample_editor_load_wav_main(const int mode, FILE* f, struct wl* wavload)
1719 {
1720     void *sbuf, *sbuf_loadto, *tmp, *sbuf2 = NULL;
1721 #if USE_SNDFILE
1722     sf_count_t len;
1723 #else
1724     int len;
1725 #endif
1726     int i, count;
1727     float rate;
1728     STSample* next = NULL;
1729 
1730     if (mode == MODE_STEREO_2) {
1731         gint n_cur;
1732 
1733         if ((n_cur = modinfo_get_current_sample()) == 127) {
1734             static GtkWidget* dialog = NULL;
1735 
1736             gui_warning_dialog(&dialog, _("You have selected the last sample of the instrument, but going "
1737                                           "to load the second stereo channel to the next sample. Please select "
1738                                           "a sample slot with lower number or use another loading mode."),
1739                 FALSE);
1740             return TRUE;
1741         }
1742         next = &(instrument_editor_get_instrument()->samples[n_cur + 1]);
1743         if (next->sample.length) {
1744             if (!gui_ok_cancel_modal(mainwindow, _("The next sample which is about to be overwritten is not empty!\n"
1745                                                    "Would you like to overwrite it?")))
1746                 return TRUE;
1747         }
1748     }
1749 
1750     if (!check_and_log_smp_ins(N_("Sample loading"), mode, current_sample, next, wavload->frameCount))
1751         return FALSE;
1752     gui_statusbar_update(STATUS_LOADING_SAMPLE, TRUE);
1753 
1754     len = 2 * wavload->frameCount * wavload->channelCount;
1755     if (!(tmp = malloc(len))) {
1756         gui_oom_error();
1757         goto errnobuf;
1758     }
1759     if (mode == MODE_MONO)
1760         sbuf = tmp;
1761     else if (!(sbuf = malloc(2 * wavload->frameCount))) {
1762         gui_oom_error();
1763         free(tmp);
1764         goto errnobuf;
1765     }
1766 
1767     if (wavload->sampleWidth == 16) {
1768         sbuf_loadto = tmp;
1769     } else {
1770         sbuf_loadto = tmp + len / 2;
1771     }
1772 
1773     if (wavload->through_library) {
1774 #if USE_SNDFILE
1775         if (wavload->frameCount != sf_readf_short(wavload->file, sbuf_loadto, wavload->frameCount)) {
1776 #else
1777         if (wavload->frameCount != afReadFrames(wavload->file, AF_DEFAULT_TRACK, sbuf_loadto, wavload->frameCount)) {
1778 #endif
1779             static GtkWidget* dialog = NULL;
1780 
1781             gui_error_dialog(&dialog, _("Read error."), FALSE);
1782             goto errnodata;
1783         }
1784     } else {
1785         if (!f)
1786             goto errnodata;
1787         if (wavload->frameCount != fread(sbuf_loadto, wavload->channelCount * wavload->sampleWidth / 8, wavload->frameCount, f)) {
1788             static GtkWidget* dialog = NULL;
1789 
1790             fclose(f);
1791             gui_error_dialog(&dialog, _("Read error."), FALSE);
1792             goto errnodata;
1793         }
1794     }
1795 
1796     if (wavload->sampleWidth == 8) {
1797         if (wavload->through_library || wavload->unsignedwords) {
1798             st_sample_8bit_signed_unsigned(sbuf_loadto, len / 2);
1799         }
1800         st_convert_sample(sbuf_loadto,
1801             tmp,
1802             8,
1803             16,
1804             len / 2);
1805     } else {
1806         if (wavload->through_library) {
1807             // I think that is what the virtualByteOrder stuff is for.
1808             // le_16_array_to_host_order(sbuf, len / 2);
1809         } else {
1810 #ifdef WORDS_BIGENDIAN
1811             if (wavload->endianness == 0) {
1812 #else
1813             if (wavload->endianness == 1) {
1814 #endif
1815                 byteswap_16_array(tmp, len / 2);
1816             }
1817             if (wavload->unsignedwords) {
1818                 st_sample_16bit_signed_unsigned(sbuf_loadto, len / 2);
1819             }
1820         }
1821     }
1822 
1823     sample_editor_lock_sample();
1824     sample_editor_init_sample(wavload->samplename);
1825     current_sample->sample.data = sbuf;
1826     current_sample->treat_as_8bit = (wavload->sampleWidth == 8);
1827     current_sample->sample.length = wavload->frameCount;
1828 
1829     // Initialize relnote and finetune such that sample is played in original speed
1830     if (wavload->through_library) {
1831 #if USE_SNDFILE
1832         current_sample->treat_as_8bit = ((wavload->wavinfo.format & (SF_FORMAT_PCM_S8 | SF_FORMAT_PCM_U8)) != 0);
1833         rate = wavload->wavinfo.samplerate;
1834 #else
1835         rate = afGetRate(wavload->file, AF_DEFAULT_TRACK);
1836 #endif
1837     } else {
1838         rate = wavload->rate;
1839     }
1840     xm_freq_note_to_relnote_finetune(rate,
1841         4 * 12 + 1, // at C-4
1842         &current_sample->relnote,
1843         &current_sample->finetune);
1844 
1845     if (mode == MODE_STEREO_2) {
1846         if (!(sbuf2 = malloc(2 * wavload->frameCount))) {
1847             gui_oom_error();
1848             goto errnodata;
1849         }
1850 
1851         g_mutex_lock(&next->sample.lock);
1852         sample_editor_init_sample_full(next, wavload->samplename);
1853         next->sample.data = sbuf2;
1854         next->treat_as_8bit = (wavload->sampleWidth == 8);
1855         next->sample.length = wavload->frameCount;
1856 
1857         xm_freq_note_to_relnote_finetune(rate,
1858             4 * 12 + 1, // at C-4
1859             &next->relnote,
1860             &next->finetune);
1861     }
1862 
1863     if (mode != MODE_MONO) {
1864         gint16 *a = tmp, *b = sbuf, *c = sbuf2;
1865 
1866         count = wavload->frameCount;
1867 
1868         /* Code could probably be made shorter. But this is readable. */
1869         switch (mode) {
1870         case MODE_STEREO_MIX:
1871             for (i = 0; i < count; i++, a += 2, b += 1)
1872                 *b = (a[0] + a[1]) / 2;
1873             break;
1874         case MODE_STEREO_2:
1875             for (i = 0; i < count; i++, a += 2, b += 1, c += 1) {
1876                 *b = a[0];
1877                 *c = a[1];
1878             }
1879             break;
1880         case MODE_STEREO_LEFT:
1881             for (i = 0; i < count; i++, a += 2, b += 1)
1882                 *b = a[0];
1883             break;
1884         case MODE_STEREO_RIGHT:
1885             for (i = 0; i < count; i++, a += 2, b += 1)
1886                 *b = a[1];
1887             break;
1888         default:
1889             g_assert_not_reached();
1890             break;
1891         }
1892     }
1893     if (sbuf != tmp)
1894         free(tmp);
1895 
1896     if (mode == MODE_STEREO_2) {
1897         if (gui_playing_mode) {
1898             mixer->updatesample(&next->sample);
1899         }
1900         g_mutex_unlock(&next->sample.lock);
1901     }
1902     sample_editor_unlock_sample();
1903 
1904     instrument_editor_update(TRUE);
1905     sample_editor_update();
1906     gui_statusbar_update(STATUS_SAMPLE_LOADED, FALSE);
1907     return FALSE;
1908 
1909 errnodata:
1910     free(sbuf);
1911     if (sbuf != tmp)
1912         free(tmp);
1913 errnobuf:
1914     gui_statusbar_update(STATUS_IDLE, FALSE);
1915     return FALSE;
1916 }
1917 
1918 static void
1919 sample_editor_open_stereowav_dialog(FILE* f, struct wl* wavload)
1920 {
1921     static GtkWidget* window = NULL;
1922     gboolean replay;
1923     gint response;
1924     gchar* buf;
1925 
1926     buf = g_strdup_printf(_("You have selected a stereo sample!\n(%s can only handle mono samples!)\n\n"
1927         "Please choose which channel to load:"), PACKAGE_NAME);
1928 
1929     sample_editor_open_stereo_dialog(&window, load_radio, buf, N_("Stereo sample loading"));
1930     g_free(buf);
1931 
1932     do {
1933         response = gtk_dialog_run(GTK_DIALOG(window));
1934 
1935         gtk_widget_hide(window);
1936         if (response != GTK_RESPONSE_OK)
1937             return;
1938 
1939         response = find_current_toggle(load_radio, 4) + 1; /* +1 since 0 means mono mode */
1940         replay = sample_editor_load_wav_main(response, f, wavload);
1941     } while (replay);
1942 }
1943 
1944 static void
1945 sample_editor_open_raw_sample_dialog(FILE* f, struct wl* wavload)
1946 {
1947     static GtkWidget *window = NULL, *combo;
1948     static GtkListStore* ls;
1949 
1950     GtkWidget* box1;
1951     GtkWidget* box2;
1952     GtkWidget* separator;
1953     GtkWidget* label;
1954     GtkWidget* thing;
1955     GtkTreeIter iter;
1956     gint response, i, active = 0;
1957 
1958     static const char* resolutionlabels[] = { N_("8 bits"), N_("16 bits") };
1959     static const char* signedlabels[] = { N_("Signed"), N_("Unsigned") };
1960     static const char* endianlabels[] = { N_("Little-Endian"), N_("Big-Endian") };
1961     static const char* channelslabels[] = { N_("Mono"), N_("Stereo") };
1962 
1963     // Standard sampling rates
1964     static const guint rates[] = { 8000, 8363, 11025, 12000, 16000, 22050, 24000, 32000, 33452, 44100, 48000 };
1965 
1966     if (!window) {
1967         window = gtk_dialog_new_with_buttons(_("Load raw sample"), GTK_WINDOW(mainwindow), GTK_DIALOG_MODAL,
1968             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1969 
1970         wavload_dialog = window;
1971         gui_dialog_adjust(window, GTK_RESPONSE_OK);
1972 
1973         box1 = gtk_dialog_get_content_area(GTK_DIALOG(window)); // upper part (vbox)
1974 
1975         label = gtk_label_new(_("You have selected a sample that is not\nin a known format. You can load the raw data now.\n\nPlease choose a format:"));
1976         gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
1977         gtk_box_pack_start(GTK_BOX(box1), label, FALSE, TRUE, 0);
1978         gtk_widget_show(label);
1979 
1980         separator = gtk_hseparator_new();
1981         gtk_box_pack_start(GTK_BOX(box1), separator, FALSE, TRUE, 5);
1982         gtk_widget_show(separator);
1983 
1984         // The toggles
1985 
1986         box2 = gtk_hbox_new(FALSE, 4);
1987         gtk_widget_show(box2);
1988         gtk_box_pack_start(GTK_BOX(box1), box2, FALSE, TRUE, 0);
1989 
1990         thing = gtk_label_new(_("Resolution:"));
1991         gtk_widget_show(thing);
1992         gtk_box_pack_start(GTK_BOX(box2), thing, FALSE, TRUE, 0);
1993         add_empty_hbox(box2);
1994         make_radio_group(resolutionlabels, box2, wavload_raw_resolution_w,
1995             FALSE, TRUE, NULL);
1996 
1997         box2 = gtk_hbox_new(FALSE, 4);
1998         gtk_widget_show(box2);
1999         gtk_box_pack_start(GTK_BOX(box1), box2, FALSE, TRUE, 0);
2000 
2001         thing = gtk_label_new(_("Word format:"));
2002         gtk_widget_show(thing);
2003         gtk_box_pack_start(GTK_BOX(box2), thing, FALSE, TRUE, 0);
2004         add_empty_hbox(box2);
2005         make_radio_group(signedlabels, box2, wavload_raw_signed_w,
2006             FALSE, TRUE, NULL);
2007 
2008         box2 = gtk_hbox_new(FALSE, 4);
2009         gtk_widget_show(box2);
2010         gtk_box_pack_start(GTK_BOX(box1), box2, FALSE, TRUE, 0);
2011 
2012         add_empty_hbox(box2);
2013         make_radio_group(endianlabels, box2, wavload_raw_endian_w,
2014             FALSE, TRUE, NULL);
2015 
2016         box2 = gtk_hbox_new(FALSE, 4);
2017         gtk_widget_show(box2);
2018         gtk_box_pack_start(GTK_BOX(box1), box2, FALSE, TRUE, 0);
2019 
2020         thing = gtk_label_new(_("Channels:"));
2021         gtk_widget_show(thing);
2022         gtk_box_pack_start(GTK_BOX(box2), thing, FALSE, TRUE, 0);
2023         add_empty_hbox(box2);
2024         make_radio_group(channelslabels, box2, wavload_raw_channels_w,
2025             FALSE, TRUE, NULL);
2026 
2027         // Rate selection combo
2028         box2 = gtk_hbox_new(FALSE, 4);
2029         gtk_widget_show(box2);
2030         gtk_box_pack_start(GTK_BOX(box1), box2, FALSE, TRUE, 0);
2031 
2032         thing = gtk_label_new(_("Sampling Rate:"));
2033         gtk_widget_show(thing);
2034         gtk_box_pack_start(GTK_BOX(box2), thing, FALSE, TRUE, 0);
2035         add_empty_hbox(box2);
2036 
2037         ls = gtk_list_store_new(1, G_TYPE_UINT);
2038         for (i = 0; i < ARRAY_SIZE(rates); i++) {
2039             gtk_list_store_append(ls, &iter);
2040             gtk_list_store_set(ls, &iter, 0, rates[i], -1);
2041             if (rates[i] == 8363)
2042                 active = i;
2043         }
2044 
2045         combo = gui_combo_new(ls);
2046         gtk_box_pack_start(GTK_BOX(box2), combo, FALSE, TRUE, 0);
2047         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), active); // default is 8363
2048         gtk_widget_show(combo);
2049 
2050         thing = gtk_hseparator_new();
2051         gtk_box_pack_end(GTK_BOX(box1), thing, FALSE, FALSE, 4);
2052         gtk_widget_show(thing);
2053         gtk_widget_show(window);
2054     } else
2055         gtk_window_present(GTK_WINDOW(window));
2056 
2057     response = gtk_dialog_run(GTK_DIALOG(window));
2058     gtk_widget_hide(window);
2059 
2060     if (response == GTK_RESPONSE_OK) {
2061         wavload->sampleWidth = find_current_toggle(wavload_raw_resolution_w, 2) == 1 ? 16 : 8;
2062         wavload->endianness = find_current_toggle(wavload_raw_endian_w, 2);
2063         wavload->channelCount = find_current_toggle(wavload_raw_channels_w, 2) == 1 ? 2 : 1;
2064         wavload->unsignedwords = find_current_toggle(wavload_raw_signed_w, 2);
2065 
2066         if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter))
2067             wavload->rate = 8363;
2068         else
2069             gtk_tree_model_get(GTK_TREE_MODEL(ls), &iter, 0, &wavload->rate, -1);
2070 
2071         if (wavload->sampleWidth == 16) {
2072             wavload->frameCount /= 2;
2073         }
2074 
2075         if (wavload->channelCount == 2) {
2076             wavload->frameCount /= 2;
2077             sample_editor_open_stereowav_dialog(f, wavload);
2078         } else {
2079             sample_editor_load_wav_main(MODE_MONO, f, wavload);
2080         }
2081     }
2082 }
2083 
2084 static void
2085 sample_editor_load_wav(const gchar* fn, const gchar* localname)
2086 {
2087     struct wl wavload;
2088 
2089 #if USE_SNDFILE != 1
2090     int sampleFormat;
2091 #endif
2092     g_return_if_fail(current_sample != NULL);
2093 
2094     wavload.samplename = strrchr(fn, '/');
2095     if (!wavload.samplename)
2096         wavload.samplename = fn;
2097     else
2098         wavload.samplename++;
2099 
2100 #if USE_SNDFILE
2101     wavload.wavinfo.format = 0;
2102     wavload.file = sf_open(localname, SFM_READ, &wavload.wavinfo);
2103 #else
2104     wavload.file = afOpenFile(localname, "r", NULL);
2105 #endif
2106     if (!wavload.file) {
2107         FILE* f = gui_fopen(localname, fn, "rb");
2108 
2109         if (f) {
2110             fseek(f, 0, SEEK_END);
2111             wavload.frameCount = ftell(f);
2112             fseek(f, 0, SEEK_SET);
2113             wavload.through_library = FALSE;
2114             sample_editor_open_raw_sample_dialog(f, &wavload);
2115             fclose(f);
2116         }
2117         return;
2118     }
2119 
2120     wavload.through_library = TRUE;
2121 
2122 #if USE_SNDFILE
2123     wavload.frameCount = wavload.wavinfo.frames;
2124 #else
2125     wavload.frameCount = afGetFrameCount(wavload.file, AF_DEFAULT_TRACK);
2126 #endif
2127     if (wavload.frameCount > mixer->max_sample_length) {
2128         static GtkWidget* dialog = NULL;
2129         gui_warning_dialog(&dialog, _("Sample is too long for current mixer module. Loading anyway."), FALSE);
2130     }
2131 
2132 #if USE_SNDFILE
2133 
2134     wavload.channelCount = wavload.wavinfo.channels;
2135     wavload.sampleWidth = 16;
2136 
2137 #else
2138 
2139     wavload.channelCount = afGetChannels(wavload.file, AF_DEFAULT_TRACK);
2140     afGetSampleFormat(wavload.file, AF_DEFAULT_TRACK, &sampleFormat, &wavload.sampleWidth);
2141 
2142     /* I think audiofile-0.1.7 does this automatically, but I'm not sure */
2143 #ifdef WORDS_BIGENDIAN
2144     afSetVirtualByteOrder(wavload.file, AF_DEFAULT_TRACK, AF_BYTEORDER_BIGENDIAN);
2145 #else
2146     afSetVirtualByteOrder(wavload.file, AF_DEFAULT_TRACK, AF_BYTEORDER_LITTLEENDIAN);
2147 #endif
2148 
2149 #endif
2150 
2151     if ((wavload.sampleWidth != 16 && wavload.sampleWidth != 8) || wavload.channelCount > 2) {
2152         static GtkWidget* dialog = NULL;
2153 
2154         gui_error_dialog(&dialog, _("Can only handle 8 and 16 bit samples with up to 2 channels"), FALSE);
2155     } else {
2156         if (wavload.channelCount == 1) {
2157             sample_editor_load_wav_main(MODE_MONO, NULL, &wavload);
2158         } else {
2159             sample_editor_open_stereowav_dialog(NULL, &wavload);
2160         }
2161     }
2162 
2163 #if USE_SNDFILE
2164     sf_close(wavload.file);
2165 #else
2166     afCloseFile(wavload.file);
2167 #endif
2168     return;
2169 }
2170 
2171 static void
2172 sample_editor_save_wav_main(const gchar* fn,
2173     const gchar* localname,
2174     guint32 offset,
2175     guint32 length)
2176 {
2177 #if USE_SNDFILE
2178     SNDFILE* outfile;
2179     SF_INFO sfinfo;
2180     int rate = 44100;
2181 #else
2182     AFfilehandle outfile;
2183     AFfilesetup outfilesetup;
2184     double rate = 44100.0;
2185 #endif
2186 
2187     gui_statusbar_update(STATUS_SAVING_SAMPLE, TRUE);
2188 
2189 #if USE_SNDFILE
2190     if (current_sample->treat_as_8bit) {
2191         sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_U8;
2192     } else {
2193         sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
2194     }
2195     sfinfo.channels = 1;
2196     sfinfo.samplerate = rate;
2197     outfile = sf_open(fn, SFM_WRITE, &sfinfo);
2198 #else
2199     outfilesetup = afNewFileSetup();
2200     afInitFileFormat(outfilesetup, AF_FILE_WAVE);
2201     afInitChannels(outfilesetup, AF_DEFAULT_TRACK, 1);
2202     if (current_sample->treat_as_8bit) {
2203 #if AUDIOFILE_VERSION == 1
2204         // for audiofile-0.1.x
2205         afInitSampleFormat(outfilesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 8);
2206 #else
2207         // for audiofile-0.2.x and 0.3.x
2208         afInitSampleFormat(outfilesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_UNSIGNED, 8);
2209 #endif
2210     } else {
2211         afInitSampleFormat(outfilesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
2212     }
2213     afInitRate(outfilesetup, AF_DEFAULT_TRACK, rate);
2214     outfile = afOpenFile(localname, "w", outfilesetup);
2215     afFreeFileSetup(outfilesetup);
2216 #endif
2217 
2218     if (!outfile) {
2219         static GtkWidget* dialog = NULL;
2220 
2221         gui_error_dialog(&dialog, _("Can't open file for writing."), FALSE);
2222         return;
2223     }
2224 
2225 #if USE_SNDFILE
2226     sf_writef_short(outfile,
2227         current_sample->sample.data + offset,
2228         length);
2229     sf_close(outfile);
2230 #else
2231     if (current_sample->treat_as_8bit) {
2232         void* buf = malloc(1 * length);
2233         g_assert(buf);
2234         st_convert_sample(current_sample->sample.data + offset,
2235             buf,
2236             16,
2237             8,
2238             length);
2239         st_sample_8bit_signed_unsigned(buf,
2240             length);
2241 
2242         afWriteFrames(outfile, AF_DEFAULT_TRACK,
2243             buf,
2244             length);
2245         free(buf);
2246     } else {
2247         afWriteFrames(outfile, AF_DEFAULT_TRACK,
2248             current_sample->sample.data + offset,
2249             length);
2250     }
2251     afCloseFile(outfile);
2252 #endif
2253 
2254     gui_statusbar_update(STATUS_SAMPLE_SAVED, FALSE);
2255 }
2256 
2257 static void
2258 sample_editor_save_wav(const gchar* fn, const gchar* localname)
2259 {
2260     g_return_if_fail(current_sample != NULL);
2261     if (current_sample->sample.data == NULL) {
2262         return;
2263     }
2264     sample_editor_save_wav_main(fn, localname, 0, current_sample->sample.length);
2265 }
2266 
2267 static void
2268 sample_editor_save_region_wav(const gchar* fn, const gchar* localname)
2269 {
2270     int rss = sampledisplay->sel_start, rse = sampledisplay->sel_end;
2271 
2272     g_return_if_fail(current_sample != NULL);
2273     if (current_sample->sample.data == NULL) {
2274         return;
2275     }
2276 
2277     if (rss == -1) {
2278         static GtkWidget* dialog = NULL;
2279         gui_error_dialog(&dialog, _("Please select region first."), FALSE);
2280         return;
2281     }
2282     sample_editor_save_wav_main(fn, localname, rss, rse - rss);
2283 }
2284 
2285 #endif /* USE_SNDFILE || AUDIOFILE_VERSION */
2286 
2287 /* ============================ Sampling functions coming up -------- */
2288 
2289 void
2290 sample_editor_clear_buffers(STSampleChain* bufs)
2291 {
2292     STSampleChain *r, *r2;
2293 
2294     /* Free allocated sample buffers */
2295     for (r = bufs; r; r = r2) {
2296         r2 = r->next;
2297         free(r->data);
2298         free(r);
2299     }
2300 }
2301 
2302 static void
2303 enable_widgets(gboolean enable)
2304 {
2305     gtk_widget_set_sensitive(okbutton, enable);
2306     gtk_widget_set_sensitive(clearbutton, enable);
2307 }
2308 
2309 static void
2310 sampling_response(GtkWidget* dialog, gint response, GtkToggleButton* button)
2311 {
2312     gtk_widget_hide(samplingwindow);
2313     sampling = FALSE;
2314 
2315     if (button->active) {
2316         g_signal_handler_block(G_OBJECT(button), toggled_id); /* To prevent data storing on record stop */
2317         gtk_toggle_button_set_active(button, FALSE);
2318         g_signal_handler_unblock(G_OBJECT(button), toggled_id);
2319     }
2320     if (monitoring) {
2321         monitoring = FALSE;
2322         sampling_driver->release(sampling_driver_object);
2323     }
2324 
2325     if (response == GTK_RESPONSE_OK)
2326         sample_editor_ok_clicked();
2327 
2328     clock_stop(CLOCK(sclock));
2329     clock_set_seconds(CLOCK(sclock), 0);
2330     sample_editor_clear_buffers(recordbufs);
2331     recordbufs = NULL;
2332     has_data = FALSE;
2333 }
2334 
2335 static void
2336 sampling_widget_hide(GtkToggleButton* button)
2337 {
2338     sampling_response(NULL, GTK_RESPONSE_CANCEL, button);
2339 }
2340 
2341 static void
2342 record_toggled(GtkWidget* button)
2343 {
2344     if (GTK_TOGGLE_BUTTON(button)->active) {
2345         enable_widgets(FALSE);
2346         recordedlen = 0;
2347         if (recordbufs) {
2348             sample_editor_clear_buffers(recordbufs);
2349             recordbufs = NULL;
2350         }
2351 
2352         if (!monitoring) {
2353             sampling_driver->open(sampling_driver_object);
2354             monitoring = TRUE;
2355         }
2356         sampling = TRUE;
2357         gtk_widget_queue_draw(GTK_WIDGET(monitorscope));
2358         clock_set_seconds(CLOCK(sclock), 0);
2359         clock_start(CLOCK(sclock));
2360     } else {
2361         sampling = FALSE;
2362         monitoring = FALSE;
2363         sampling_driver->release(sampling_driver_object);
2364 
2365         has_data = TRUE;
2366         enable_widgets(has_data);
2367         // _set_chain() instead to display the whole sample
2368         if (recordbufs) /* Recordbufs might be not allocated yet */
2369             sample_display_set_data(monitorscope, recordbufs->data, format,
2370                 recordbufs->length >> (mixer_get_resolution(format) + mixer_is_format_stereo(format) - 1), FALSE);
2371         clock_stop(CLOCK(sclock));
2372     }
2373 }
2374 
2375 void
2376 clear_clicked(void)
2377 {
2378     has_data = FALSE;
2379     enable_widgets(has_data);
2380 
2381     recordedlen = 0;
2382     sample_editor_clear_buffers(recordbufs);
2383     recordbufs = NULL;
2384     if (!monitoring) {
2385         sampling_driver->open(sampling_driver_object);
2386         monitoring = TRUE;
2387     }
2388     clock_set_seconds(CLOCK(sclock), 0);
2389 }
2390 
2391 static gboolean
2392 sampling_window_keyevent(GtkWidget* widget,
2393     GdkEventKey* event, GtkToggleButton* rec_btn)
2394 {
2395     gint shift = event->state & GDK_SHIFT_MASK;
2396     gint ctrl = event->state & GDK_CONTROL_MASK;
2397     gint alt = event->state & GDK_MOD1_MASK;
2398     gint m = keys_get_key_meaning(event->keyval, ENCODE_MODIFIERS(shift, ctrl, alt), event->hardware_keycode);
2399 
2400     if (KEYS_MEANING_TYPE(m) == KEYS_MEANING_FUNC) {
2401         gboolean handled;
2402 
2403         if (KEYS_MEANING_VALUE(m) == KEY_SMP_TOGGLE) {
2404             gtk_toggle_button_set_active(rec_btn, !gtk_toggle_button_get_active(rec_btn));
2405             handled = TRUE;
2406         } else
2407             handled = gui_handle_standard_keys(shift, ctrl, alt, event->keyval, event->hardware_keycode);
2408 
2409         return handled;
2410     }
2411 
2412     if (event->keyval == ' ') {
2413         gui_play_stop();
2414         return TRUE;
2415     }
2416 
2417     return FALSE;
2418 }
2419 
2420 void
2421 sample_editor_monitor_clicked(void)
2422 {
2423     if (!sampling_driver || !sampling_driver_object) {
2424         static GtkWidget* dialog = NULL;
2425 
2426         gui_error_dialog(&dialog, _("No sampling driver available"), FALSE);
2427         return;
2428     }
2429 
2430     if (!samplingwindow) {
2431         GtkWidget *mainbox, *thing, *box2;
2432         GtkAccelGroup* group = gtk_accel_group_new();
2433         GClosure* closure;
2434 
2435         samplingwindow = gtk_dialog_new_with_buttons(_("Sampling Window"), GTK_WINDOW(mainwindow), 0,
2436             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
2437         gtk_window_add_accel_group(GTK_WINDOW(samplingwindow), group);
2438 
2439         okbutton = gtk_dialog_add_button(GTK_DIALOG(samplingwindow), GTK_STOCK_OK, GTK_RESPONSE_OK);
2440         gtk_container_set_border_width(GTK_CONTAINER(samplingwindow), 4);
2441 
2442         mainbox = gtk_dialog_get_content_area(GTK_DIALOG(samplingwindow));
2443 
2444         gtk_container_set_border_width(GTK_CONTAINER(mainbox), 4);
2445         gtk_box_set_spacing(GTK_BOX(mainbox), 2);
2446 
2447         thing = sample_display_new(FALSE, gui_settings.sampling_mode);
2448         custom_drawing_register_drawing_func(CUSTOM_DRAWING(thing), red_circle_draw, NULL);
2449         custom_drawing_register_realize_func(CUSTOM_DRAWING(thing), red_circle_realize, NULL);
2450         gtk_box_pack_start(GTK_BOX(mainbox), thing, TRUE, TRUE, 0);
2451         monitorscope = SAMPLE_DISPLAY(thing);
2452 
2453         box2 = gtk_hbox_new(FALSE, 4);
2454         gtk_box_pack_start(GTK_BOX(mainbox), box2, FALSE, TRUE, 0);
2455 
2456         thing = gtk_toggle_button_new_with_label(_("Record"));
2457         closure = g_cclosure_new_swap(G_CALLBACK(sampling_widget_hide), thing, NULL);
2458         gtk_accel_group_connect(group, GDK_Escape, 0, 0, closure);
2459         toggled_id = g_signal_connect(thing, "toggled",
2460             G_CALLBACK(record_toggled), NULL);
2461         gtk_box_pack_start(GTK_BOX(box2), thing, FALSE, FALSE, 0);
2462         gui_dialog_connect_data(samplingwindow, G_CALLBACK(sampling_response), thing);
2463         g_signal_connect(samplingwindow, "key-press-event",
2464             G_CALLBACK(sampling_window_keyevent), thing);
2465 
2466         clearbutton = thing = gtk_button_new_with_label(_("Clear"));
2467         g_signal_connect(thing, "clicked",
2468             G_CALLBACK(clear_clicked), NULL);
2469         gtk_box_pack_start(GTK_BOX(box2), thing, FALSE, FALSE, 0);
2470 
2471         sclock = clock_new();
2472         clock_set_format(CLOCK(sclock), _("%M:%S"));
2473         clock_set_seconds(CLOCK(sclock), 0);
2474         gtk_box_pack_start(GTK_BOX(box2), sclock, FALSE, TRUE, 0);
2475 
2476         thing = gtk_hseparator_new();
2477         gtk_box_pack_start(GTK_BOX(mainbox), thing, FALSE, FALSE, 4);
2478 
2479         gtk_widget_show_all(samplingwindow);
2480     } else
2481         gtk_window_present(GTK_WINDOW(samplingwindow));
2482 
2483     enable_widgets(FALSE);
2484     gtk_window_set_focus(GTK_WINDOW(samplingwindow), NULL);
2485 
2486     recordbufs = NULL;
2487     sampling = FALSE;
2488     has_data = FALSE;
2489     recordedlen = 0;
2490     current = NULL;
2491     rate = 44100;
2492     format = ST_MIXER_FORMAT_S16_LE;
2493 
2494     if (!sampling_driver->open(sampling_driver_object)) {
2495         static GtkWidget* dialog = NULL;
2496 
2497         sample_editor_stop_sampling();
2498         gui_error_dialog(&dialog, _("Sampling failed!"), FALSE);
2499     } else
2500         monitoring = TRUE;
2501 }
2502 
2503 static gboolean
2504 monitorscope_queue(SampleDisplay* mscope)
2505 {
2506     sample_display_set_data(mscope, monitor_buf, format,
2507         monitor_count >> (mixer_get_resolution(format) + mixer_is_format_stereo(format) - 1), FALSE);
2508 
2509     return FALSE;
2510 }
2511 
2512 /* Count is in bytes, not samples. The function returns TRUE if the buffer is acquired and the driver shall allocate a new one */
2513 gboolean
2514 sample_editor_sampled(void* src,
2515     guint32 count,
2516     gint mixfreq,
2517     gint mixformat)
2518 {
2519     gboolean sampled = FALSE;
2520 
2521     if (monitoring) {
2522         /* Actual data for sample monitor */
2523         format = mixformat;
2524         monitor_count = count;
2525         monitor_buf = src;
2526         g_idle_add((GSourceFunc)monitorscope_queue, (gpointer)monitorscope);
2527 
2528         if (sampling) {
2529             STSampleChain *newbuf = malloc(sizeof(STSampleChain));
2530 
2531             if (!newbuf) {
2532                 /* It is called from audio thread AFAIK */
2533                 error_error(_("Out of memory while sampling!"));
2534                 sampling = 0;
2535                 return FALSE;
2536             }
2537             newbuf->next = NULL;
2538             newbuf->length = count;
2539             newbuf->data = src;
2540 
2541             if (!recordbufs){ /* Sampling start */
2542                 recordbufs = newbuf;
2543                 rate = mixfreq;
2544             } else
2545                 current->next = newbuf;
2546 
2547             current = newbuf;
2548             sampled = TRUE;
2549             recordedlen += count;
2550         }
2551     }
2552 
2553     return sampled;
2554 }
2555 
2556 void sample_editor_stop_sampling(void)
2557 {
2558 
2559     sampling = FALSE;
2560     has_data = FALSE;
2561 
2562     if (samplingwindow) {
2563         if (monitoring) {
2564             monitoring = FALSE;
2565             sampling_driver->release(sampling_driver_object);
2566         }
2567         gtk_widget_hide(samplingwindow);
2568 
2569         sample_editor_clear_buffers(recordbufs);
2570         recordbufs = NULL;
2571     }
2572 }
2573 
2574 void
2575 sample_editor_chain_to_sample(STSampleChain *rbufs,
2576     guint32 rlen,
2577     STMixerFormat fmt,
2578     guint32 srate,
2579     const gboolean data_present,
2580     const gchar* samplename,
2581     const gchar* action,
2582     const gchar* log_name)
2583 {
2584     STInstrument* instr;
2585     STSample* next = NULL;
2586     STSampleChain *r;
2587     gint16 *sbuf, *sbuf2 = NULL;
2588     guint multiply, mode = 0;
2589     gboolean stereo = mixer_is_format_stereo(fmt);
2590 
2591     g_return_if_fail(current_sample != NULL && data_present);
2592 
2593     fmt &= 0x7;
2594     multiply = mixer_get_resolution(fmt) - 1; /* 0 - 8 bit, 1 - 16, used for shifts */
2595     if (!stereo && !multiply) /* 8bit mono */
2596         rlen <<= 1;
2597     else if (stereo && multiply) /* 16 bit stereo */
2598         rlen >>= 1;
2599 
2600     if (stereo) {
2601         static GtkWidget* window = NULL;
2602         gboolean replay;
2603         gchar* buf;
2604 
2605         buf = g_strdup_printf(_("You have %s a stereo sample!\n(%s can only handle mono samples!)\n\n"
2606         "Please choose which channel to use:"), _(action), PACKAGE_NAME);
2607         sample_editor_open_stereo_dialog(&window, record_radio, buf, N_("Converting stereo sample"));
2608         g_free(buf);
2609 
2610         do {
2611             gint n_cur;
2612 
2613             replay = FALSE;
2614 
2615             mode = gtk_dialog_run(GTK_DIALOG(window));
2616             gtk_widget_hide(window);
2617 
2618             if (mode != GTK_RESPONSE_OK)
2619                 mode = 0; /* Cancelling or other possible unclear status -- do nothing */
2620             else
2621                 mode = find_current_toggle(record_radio, 4) + 1; /* +1 since 0 means mono mode */
2622             switch (mode) {
2623             case MODE_STEREO_LEFT:
2624             case MODE_STEREO_MIX:
2625             case MODE_STEREO_RIGHT:
2626                 break;
2627             case MODE_STEREO_2:
2628                 if ((n_cur = modinfo_get_current_sample()) == 127) {
2629                     static GtkWidget* dialog = NULL;
2630 
2631                     gui_warning_dialog(&dialog, _("You have selected the last sample of the instrument, but going "
2632                                                   "to load the second stereo channel to the next sample. Please select "
2633                                                   "a sample slot with lower number or use another loading mode."),
2634                         FALSE);
2635                     replay = TRUE;
2636                 }
2637                 next = &(instrument_editor_get_instrument()->samples[n_cur + 1]);
2638                 if (next->sample.length)
2639                     replay = !gui_ok_cancel_modal(mainwindow, _("The next sample which is about to be overwritten is not empty!\n"
2640                                                                 "Would you like to overwrite it?"));
2641                 break;
2642             default:
2643                 return;
2644             }
2645         } while (replay);
2646     }
2647 
2648     if (!(sbuf = malloc(rlen))) {
2649         gui_oom_error();
2650         return;
2651     }
2652 
2653     if (mode == MODE_STEREO_2)
2654         if (!(sbuf2 = malloc(rlen))) {
2655             gui_oom_error();
2656             free(sbuf);
2657             return;
2658         }
2659 
2660     if (!check_and_log_smp_ins(log_name, mode, current_sample, next, rlen >> 1))
2661         return;
2662 
2663     sample_editor_lock_sample();
2664     st_clean_sample(current_sample, NULL, NULL);
2665     instr = instrument_editor_get_instrument();
2666     if (st_instrument_num_samples(instr) == 0)
2667         st_clean_instrument(instr, samplename);
2668     st_clean_sample(current_sample, samplename, NULL);
2669     current_sample->sample.data = sbuf;
2670 
2671     if (mode == MODE_STEREO_2) {
2672 
2673         g_mutex_lock(&next->sample.lock);
2674         st_clean_sample(next, samplename, NULL);
2675         next->sample.data = sbuf2;
2676         next->treat_as_8bit = !multiply;
2677         next->sample.length = rlen >> 1; /* Sample size is given in 16-bit words */
2678         next->volume = 64;
2679         next->panning = 128;
2680 
2681         xm_freq_note_to_relnote_finetune(srate,
2682             4 * 12 + 1, // at C-4
2683             &next->relnote,
2684             &next->finetune);
2685     }
2686 
2687     for (r = rbufs; r; r = r->next) {
2688         guint j;
2689 
2690 #ifdef WORDS_BIGENDIAN
2691         if (fmt == ST_MIXER_FORMAT_S16_LE || fmt == ST_MIXER_FORMAT_U16_LE)
2692 #else
2693         if (fmt == ST_MIXER_FORMAT_S16_BE || fmt == ST_MIXER_FORMAT_U16_BE)
2694 #endif
2695             byteswap_16_array(r->data, r->length);
2696 
2697         if (stereo) { /* Looks awfully, but this is the only way to handle this plenty of format combination */
2698             switch (mode) {
2699             case MODE_STEREO_LEFT:
2700                 switch (fmt) {
2701                 case ST_MIXER_FORMAT_S16_LE:
2702                 case ST_MIXER_FORMAT_S16_BE:
2703                     for (j = 0; j<r->length>> 1; j += 2, sbuf++)
2704                         *sbuf = ((gint16*)r->data)[j];
2705                     break;
2706                 case ST_MIXER_FORMAT_U16_LE:
2707                 case ST_MIXER_FORMAT_U16_BE:
2708                     for (j = 0; j<r->length>> 1; j += 2, sbuf++)
2709                         *sbuf = ((gint16*)r->data)[j] - 32768;
2710                     break;
2711                 case ST_MIXER_FORMAT_S8:
2712                     for (j = 0; j < r->length; j += 2, sbuf++)
2713                         *sbuf = ((gint8*)r->data)[j] << 8;
2714                     break;
2715                 case ST_MIXER_FORMAT_U8:
2716                     for (j = 0; j < r->length; j += 2, sbuf++)
2717                         *sbuf = (((gint8*)r->data)[j] << 8) - 32768;
2718                     break;
2719                 default:
2720                     memset(sbuf, 0, r->length);
2721                     sbuf += r->length >> 1; /* Unknown format */
2722                 }
2723                 break;
2724             case MODE_STEREO_MIX:
2725                 switch (fmt) {
2726                 case ST_MIXER_FORMAT_S16_LE:
2727                 case ST_MIXER_FORMAT_S16_BE:
2728                     for (j = 0; j<r->length>> 1; j += 2, sbuf++)
2729                         *sbuf = (((gint16*)r->data)[j] + ((gint16*)r->data)[j + 1]) >> 1;
2730                     break;
2731                 case ST_MIXER_FORMAT_U16_LE:
2732                 case ST_MIXER_FORMAT_U16_BE:
2733                     for (j = 0; j<r->length>> 1; j += 2, sbuf++)
2734                         *sbuf = ((((gint16*)r->data)[j] + ((gint16*)r->data)[j + 1]) >> 1) - 32768;
2735                     break;
2736                 case ST_MIXER_FORMAT_S8:
2737                     for (j = 0; j < r->length; j += 2, sbuf++)
2738                         *sbuf = (((gint8*)r->data)[j] + ((gint8*)r->data)[j + 1]) << 7;
2739                     break;
2740                 case ST_MIXER_FORMAT_U8:
2741                     for (j = 0; j < r->length; j += 2, sbuf++)
2742                         *sbuf = ((((gint8*)r->data)[j] + ((gint8*)r->data)[j + 1]) << 7) - 32768;
2743                     break;
2744                 default:
2745                     memset(sbuf, 0, r->length);
2746                     sbuf += r->length >> 1; /* Unknown format */
2747                 }
2748                 break;
2749             case MODE_STEREO_RIGHT:
2750                 switch (fmt) {
2751                 case ST_MIXER_FORMAT_S16_LE:
2752                 case ST_MIXER_FORMAT_S16_BE:
2753                     for (j = 0; j<r->length>> 1; j += 2, sbuf++)
2754                         *sbuf = ((gint16*)r->data)[j + 1];
2755                     break;
2756                 case ST_MIXER_FORMAT_U16_LE:
2757                 case ST_MIXER_FORMAT_U16_BE:
2758                     for (j = 0; j<r->length>> 1; j += 2, sbuf++)
2759                         *sbuf = ((gint16*)r->data)[j + 1] - 32768;
2760                     break;
2761                 case ST_MIXER_FORMAT_S8:
2762                     for (j = 0; j < r->length; j += 2, sbuf++)
2763                         *sbuf = ((gint8*)r->data)[j + 1] << 8;
2764                     break;
2765                 case ST_MIXER_FORMAT_U8:
2766                     for (j = 0; j < r->length; j += 2, sbuf++)
2767                         *sbuf = (((gint8*)r->data)[j + 1] << 8) - 32768;
2768                     break;
2769                 default:
2770                     memset(sbuf, 0, r->length);
2771                     sbuf += r->length >> 1; /* Unknown format */
2772                 }
2773                 break;
2774             case MODE_STEREO_2:
2775                 switch (fmt) {
2776                 case ST_MIXER_FORMAT_S16_LE:
2777                 case ST_MIXER_FORMAT_S16_BE:
2778                     for (j = 0; j<r->length>> 1; j += 2, sbuf++, sbuf2++) {
2779                         *sbuf = ((gint16*)r->data)[j];
2780                         *sbuf2 = ((gint16*)r->data)[j + 1];
2781                     }
2782                     break;
2783                 case ST_MIXER_FORMAT_U16_LE:
2784                 case ST_MIXER_FORMAT_U16_BE:
2785                     for (j = 0; j<r->length>> 1; j += 2, sbuf++, sbuf2++) {
2786                         *sbuf = ((gint16*)r->data)[j] - 32768;
2787                         *sbuf2 = ((gint16*)r->data)[j + 1] - 32768;
2788                     }
2789                     break;
2790                 case ST_MIXER_FORMAT_S8:
2791                     for (j = 0; j < r->length; j += 2, sbuf++, sbuf2++) {
2792                         *sbuf = ((gint8*)r->data)[j] << 8;
2793                         *sbuf2 = ((gint8*)r->data)[j + 1] << 8;
2794                     }
2795                     break;
2796                 case ST_MIXER_FORMAT_U8:
2797                     for (j = 0; j < r->length; j += 2, sbuf++, sbuf2++) {
2798                         *sbuf = (((gint8*)r->data)[j] << 8) - 32768;
2799                         *sbuf2 = (((gint8*)r->data)[j + 1] << 8) - 32768;
2800                     }
2801                     break;
2802                 default:
2803                     memset(sbuf, 0, r->length); /* Unknown format */
2804                     memset(sbuf2, 0, r->length);
2805                     sbuf += r->length >> 1;
2806                     sbuf2 += r->length >> 1;
2807                 }
2808             }
2809         } else {
2810             switch (fmt) {
2811             case ST_MIXER_FORMAT_S16_LE:
2812             case ST_MIXER_FORMAT_S16_BE:
2813                 memcpy(sbuf, r->data, r->length);
2814                 sbuf += r->length >> 1;
2815                 break;
2816             case ST_MIXER_FORMAT_U16_LE:
2817             case ST_MIXER_FORMAT_U16_BE:
2818                 for (j = 0; j<r->length>> 1; j++, sbuf++)
2819                     *sbuf = ((gint16*)r->data)[j] - 32768;
2820                 break;
2821             case ST_MIXER_FORMAT_S8:
2822                 for (j = 0; j < r->length; j++, sbuf++)
2823                     *sbuf = ((gint8*)r->data)[j] << 8;
2824                 break;
2825             case ST_MIXER_FORMAT_U8:
2826                 for (j = 0; j < r->length; j++, sbuf++)
2827                     *sbuf = (((gint8*)r->data)[j] << 8) - 32768;
2828                 break;
2829             default:
2830                 memset(sbuf, 0, r->length); /* Unknown format */
2831                 sbuf += r->length >> 1;
2832             }
2833         }
2834     }
2835 
2836     if (rlen > mixer->max_sample_length) {
2837         static GtkWidget* dialog = NULL;
2838         gui_warning_dialog(&dialog, _("Recorded sample is too long for current mixer module. Using it anyway."), FALSE);
2839     }
2840 
2841     current_sample->sample.length = rlen >> 1; /* Sample size is given in 16-bit words */
2842     current_sample->volume = 64;
2843     current_sample->panning = 128;
2844     current_sample->treat_as_8bit = !multiply;
2845 
2846     xm_freq_note_to_relnote_finetune(srate,
2847         4 * 12 + 1, // at C-4
2848         &current_sample->relnote,
2849         &current_sample->finetune);
2850 
2851     sample_editor_unlock_sample();
2852     if (mode == MODE_STEREO_2) {
2853         if (gui_playing_mode) {
2854             mixer->updatesample(&next->sample);
2855         }
2856         g_mutex_unlock(&next->sample.lock);
2857     }
2858 
2859     instrument_editor_update(TRUE);
2860     sample_editor_update();
2861 }
2862 
2863 static void
2864 sample_editor_ok_clicked(void)
2865 {
2866     sample_editor_chain_to_sample(recordbufs, recordedlen, format, rate, has_data,
2867         N_("<just sampled>"), N_("recorded"), N_("Sampling"));
2868 }
2869 
2870 /* ==================== VOLUME RAMPING DIALOG =================== */
2871 
2872 static void
2873 sample_editor_lrvol(GtkWidget* widget,
2874     gpointer data)
2875 {
2876     int mode = GPOINTER_TO_INT(data);
2877 
2878     switch (mode) {
2879     case 0:
2880     case 2:
2881         gtk_spin_button_set_value(GTK_SPIN_BUTTON(sample_editor_volramp_spin_w[mode / 2]), 50);
2882         break;
2883     case 4:
2884     case 8:
2885         gtk_spin_button_set_value(GTK_SPIN_BUTTON(sample_editor_volramp_spin_w[mode / 8]), 200);
2886         break;
2887     }
2888 }
2889 
2890 static void
2891 sample_editor_perform_ramp(gint action)
2892 {
2893     double left, right;
2894     gint ss = sampledisplay->sel_start, se = sampledisplay->sel_end;
2895     gint i, m, q;
2896     gint16* p;
2897     gboolean set_selection = TRUE;
2898     const gchar* title;
2899 
2900     if (!current_sample)
2901         return;
2902     if (ss == -1) {
2903         ss = 0;
2904         se = current_sample->sample.length;
2905         set_selection = FALSE;
2906     }
2907 
2908     switch (action) {
2909     case 1:
2910         // Find maximum amplitude
2911         p = current_sample->sample.data;
2912         p += ss;
2913         for (i = 0, m = 0; i < se - ss; i++) {
2914             q = *p++;
2915             q = ABS(q);
2916             if (q > m)
2917                 m = q;
2918         }
2919         left = right = (double)0x7fff / m;
2920         title = N_("Sample normalizing");
2921         break;
2922     case 2:
2923         left = gtk_spin_button_get_value(GTK_SPIN_BUTTON(sample_editor_volramp_spin_w[0])) / 100.0;
2924         right = gtk_spin_button_get_value(GTK_SPIN_BUTTON(sample_editor_volramp_spin_w[1])) / 100.0;
2925         title = N_("Sample volume ramping");
2926         break;
2927     default:
2928         return;
2929     }
2930 
2931     if (!sample_editor_check_and_log_range(current_sample, title, HISTORY_FLAG_LOG_ALL, ss, se))
2932         return;
2933 
2934     // Now perform the actual operation
2935     sample_editor_lock_sample();
2936 
2937     p = current_sample->sample.data;
2938     p += ss;
2939     for (i = 0; i < se - ss; i++) {
2940         double q = *p;
2941         q *= left + i * (right - left) / (se - ss);
2942         *p++ = CLAMP((int)q, -32768, +32767);
2943     }
2944 
2945     sample_editor_unlock_sample();
2946     sample_editor_update();
2947     if (set_selection)
2948         sample_display_set_selection(sampledisplay, ss, se);
2949 }
2950 
2951 void
2952 sample_editor_normalize(void)
2953 {
2954     sample_editor_perform_ramp(1);
2955 }
2956 
2957 void
2958 sample_editor_open_volume_ramp_dialog(void)
2959 {
2960     static GtkWidget* volrampwindow = NULL;
2961     gint response;
2962 
2963     if (volrampwindow == NULL) {
2964         GtkWidget *mainbox, *box1, *thing;
2965 
2966         volrampwindow = gtk_dialog_new_with_buttons(_("Volume Ramping"), GTK_WINDOW(mainwindow), 0,
2967             GTK_STOCK_EXECUTE, 2,
2968             GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
2969         gui_dialog_connect(volrampwindow, G_CALLBACK(sample_editor_perform_ramp));
2970 
2971         gui_dialog_adjust(volrampwindow, 2);
2972         mainbox = gtk_dialog_get_content_area(GTK_DIALOG(volrampwindow));
2973         gtk_box_set_spacing(GTK_BOX(mainbox), 2);
2974 
2975         thing = gtk_label_new(_("Perform linear volume fade on Selection"));
2976         gtk_box_pack_start(GTK_BOX(mainbox), thing, FALSE, TRUE, 0);
2977 
2978         thing = gtk_hseparator_new();
2979         gtk_box_pack_start(GTK_BOX(mainbox), thing, FALSE, TRUE, 0);
2980 
2981         box1 = gtk_hbox_new(FALSE, 4);
2982         gtk_box_pack_start(GTK_BOX(mainbox), box1, FALSE, TRUE, 4);
2983 
2984         gui_put_labelled_spin_button(box1, _("Left [%]:"), -1000, 1000, &sample_editor_volramp_spin_w[0], NULL, NULL, FALSE);
2985         gtk_spin_button_set_value(GTK_SPIN_BUTTON(sample_editor_volramp_spin_w[0]), 100);
2986 
2987         thing = gtk_button_new_with_label(_("H"));
2988         gtk_box_pack_start(GTK_BOX(box1), thing, FALSE, TRUE, 0);
2989         gtk_widget_set_tooltip_text(thing, _("Half"));
2990         g_signal_connect(thing, "clicked",
2991             G_CALLBACK(sample_editor_lrvol), GINT_TO_POINTER(0));
2992 
2993         thing = gtk_button_new_with_label(_("D"));
2994         gtk_widget_set_tooltip_text(thing, _("Double"));
2995         gtk_box_pack_start(GTK_BOX(box1), thing, FALSE, TRUE, 0);
2996         g_signal_connect(thing, "clicked",
2997             G_CALLBACK(sample_editor_lrvol), GINT_TO_POINTER(4));
2998 
2999         add_empty_hbox(box1);
3000 
3001         gui_put_labelled_spin_button(box1, _("Right [%]:"), -1000, 1000, &sample_editor_volramp_spin_w[1], NULL, NULL, FALSE);
3002         gtk_spin_button_set_value(GTK_SPIN_BUTTON(sample_editor_volramp_spin_w[1]), 100);
3003 
3004         thing = gtk_button_new_with_label(_("H"));
3005         gtk_box_pack_start(GTK_BOX(box1), thing, FALSE, TRUE, 0);
3006         gtk_widget_set_tooltip_text(thing, _("Half"));
3007         g_signal_connect(thing, "clicked",
3008             G_CALLBACK(sample_editor_lrvol), GINT_TO_POINTER(2));
3009 
3010         thing = gtk_button_new_with_label(_("D"));
3011         gtk_box_pack_start(GTK_BOX(box1), thing, FALSE, TRUE, 0);
3012         gtk_widget_set_tooltip_text(thing, _("Double"));
3013         g_signal_connect(thing, "clicked",
3014             G_CALLBACK(sample_editor_lrvol), GINT_TO_POINTER(8));
3015 
3016         thing = gtk_hseparator_new();
3017         gtk_box_pack_start(GTK_BOX(mainbox), thing, FALSE, TRUE, 4);
3018 
3019         gtk_widget_show_all(volrampwindow);
3020     }
3021 
3022     response = gtk_dialog_run(GTK_DIALOG(volrampwindow));
3023     gtk_widget_hide(volrampwindow);
3024     sample_editor_perform_ramp(response);
3025 }
3026 
3027 /* ====================== SILENCE INSERTION ===================== */
3028 void
3029 sample_editor_insert_silence(void)
3030 {
3031     static GtkWidget *dialog = NULL;
3032     static GtkWidget *position[2], *discretes;
3033 
3034     gint response, start, length, tail;
3035     gboolean reselection = TRUE, at_beg;
3036     gint ss = sampledisplay->sel_start, se = sampledisplay->sel_end;
3037     gint ns = sampledisplay->win_start,
3038          ne = sampledisplay->win_start + sampledisplay->win_length;
3039     st_mixer_sample_info* smp;
3040 
3041     const gchar* labels[] = {
3042         N_("Before selection or at the beginnning"),
3043         N_("After selection or at the end")
3044     };
3045 
3046     if (!current_sample)
3047         return;
3048     smp = &current_sample->sample;
3049     if (!smp->length)
3050         return;
3051 
3052     if (ss == -1) {
3053         ss = 0;
3054         se = smp->length;
3055         reselection = FALSE;
3056     }
3057 
3058     if (!dialog) {
3059         GtkWidget *mainbox, *thing, *box;
3060 
3061         dialog = gtk_dialog_new_with_buttons(_("Insert silence"), GTK_WINDOW(mainwindow), GTK_DIALOG_MODAL,
3062             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
3063         gui_dialog_adjust(dialog, GTK_RESPONSE_OK);
3064         mainbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
3065         gtk_box_set_spacing(GTK_BOX(mainbox), 2);
3066 
3067         make_radio_group(labels, mainbox, position, FALSE, FALSE, NULL);
3068 
3069         box = gtk_hbox_new(FALSE, 0);
3070 
3071         thing = gtk_label_new(_("Number of discretes"));
3072         gtk_box_pack_start(GTK_BOX(box), thing, FALSE, FALSE, 0);
3073         discretes = gtk_spin_button_new(GTK_ADJUSTMENT(gtk_adjustment_new(1000.0, 1.0, INT_MAX, 1.0, 5.0, 0.0)), 0, 0);
3074         gtk_box_pack_end(GTK_BOX(box), discretes, FALSE, FALSE, 0);
3075         gtk_box_pack_start(GTK_BOX(mainbox), box, FALSE, FALSE, 0);
3076 
3077         thing = gtk_hseparator_new();
3078         gtk_box_pack_start(GTK_BOX(mainbox), thing, FALSE, FALSE, 4);
3079 
3080         gtk_widget_show_all(dialog);
3081     }
3082 
3083     response = gtk_dialog_run(GTK_DIALOG(dialog));
3084     gtk_widget_hide(dialog);
3085 
3086     if (response != GTK_RESPONSE_OK)
3087         return;
3088 
3089     length = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(discretes));
3090     if (!sample_editor_check_and_log_sample(current_sample,
3091         N_("Silence insertion"), HISTORY_FLAG_LOG_ALL, smp->length + length))
3092         return;
3093 
3094     sample_editor_lock_sample();
3095     at_beg = (find_current_toggle(position, 2) == 0);
3096     start =  at_beg ? ss : se;
3097     tail = smp->length - start;
3098     smp->length += length;
3099     smp->data = g_renew(gint16, smp->data, smp->length);
3100     memmove(&smp->data[start + length], &smp->data[start], tail * sizeof(smp->data[0]));
3101     memset(&smp->data[start], 0, length * sizeof(smp->data[0]));
3102     sample_editor_unlock_sample();
3103 
3104 
3105     if (smp->loopend > start)
3106         smp->loopend += length;
3107     if (smp->loopstart >= start) {
3108         smp->loopstart += length;
3109         /* Because loop end anyway will be changed if the loop start is changed */
3110         sample_editor_block_loop_spins(1);
3111         gtk_spin_button_set_range(GTK_SPIN_BUTTON(spin_loopstart), 0, smp->loopend - 1);
3112         gtk_spin_button_set_range(GTK_SPIN_BUTTON(spin_loopend), 1, smp->loopstart + 1);
3113         gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_loopstart), smp->loopstart);
3114         sample_editor_block_loop_spins(0);
3115         gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_loopend), smp->loopend);
3116     }
3117 
3118     sample_editor_update();
3119     sample_display_set_window(sampledisplay, ns, ne);
3120 
3121     if (reselection) {
3122         if (at_beg) {
3123             ss += length;
3124             se += length;
3125         }
3126         sample_display_set_selection(sampledisplay, ss, se);
3127     }
3128 }
3129 
3130 /* =================== TRIM AND CROP FUNCTIONS ================== */
3131 void
3132 sample_editor_trim_dialog(void)
3133 {
3134     static GtkAdjustment* adj;
3135     static GtkWidget *trimdialog = NULL, *trimbeg, *trimend;
3136     GtkWidget *mainbox, *thing, *box;
3137     gint response;
3138 
3139     if (!trimdialog) {
3140         trimdialog = gtk_dialog_new_with_buttons(_("Trim parameters"), GTK_WINDOW(mainwindow), GTK_DIALOG_MODAL,
3141             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
3142         gui_dialog_adjust(trimdialog, GTK_RESPONSE_OK);
3143         mainbox = gtk_dialog_get_content_area(GTK_DIALOG(trimdialog));
3144         gtk_box_set_spacing(GTK_BOX(mainbox), 2);
3145 
3146         trimbeg = thing = gtk_check_button_new_with_label(_("Trim at the beginning"));
3147         gtk_box_pack_start(GTK_BOX(mainbox), thing, FALSE, FALSE, 0);
3148         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(thing), TRUE);
3149 
3150         trimend = thing = gtk_check_button_new_with_label(_("Trim at the end"));
3151         gtk_box_pack_start(GTK_BOX(mainbox), thing, FALSE, FALSE, 0);
3152         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(thing), TRUE);
3153 
3154         box = gtk_hbox_new(FALSE, 0);
3155 
3156         thing = gtk_label_new(_("Threshold (dB)"));
3157         gtk_box_pack_start(GTK_BOX(box), thing, FALSE, FALSE, 0);
3158         thing = gtk_spin_button_new(adj = GTK_ADJUSTMENT(gtk_adjustment_new(-50.0, -80.0, -20.0, 1.0, 5.0, 0.0)), 0, 0);
3159         gtk_box_pack_end(GTK_BOX(box), thing, FALSE, FALSE, 0);
3160         gtk_box_pack_start(GTK_BOX(mainbox), box, FALSE, FALSE, 0);
3161 
3162         thing = gtk_hseparator_new();
3163         gtk_box_pack_start(GTK_BOX(mainbox), thing, FALSE, FALSE, 4);
3164 
3165         gtk_widget_show_all(trimdialog);
3166     } else
3167         gtk_window_present(GTK_WINDOW(trimdialog));
3168 
3169     response = gtk_dialog_run(GTK_DIALOG(trimdialog));
3170     gtk_widget_hide(trimdialog);
3171 
3172     if (response == GTK_RESPONSE_OK)
3173         sample_editor_trim(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(trimbeg)),
3174             gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(trimend)), adj->value);
3175 }
3176 
3177 static void
3178 sample_editor_trim(gboolean trbeg, gboolean trend, gfloat thrshld)
3179 {
3180     int start = sampledisplay->sel_start, end = sampledisplay->sel_end;
3181     int i, c, ofs;
3182     int amp = 0, val, bval = 0, maxamp, ground;
3183     int on, off;
3184     double avg;
3185     int reselect = 1;
3186     gint16* data;
3187 
3188     if (current_sample == NULL)
3189         return;
3190     if (!trbeg && !trend)
3191         return;
3192 
3193     /* if there's no selection, we operate on the entire sample */
3194     if (start == -1) {
3195         start = 0;
3196         end = current_sample->sample.length;
3197         reselect = 0;
3198     }
3199 
3200     data = current_sample->sample.data;
3201     /* Finding the maximum amplitude */
3202     for (i = 0, maxamp = 0; i < end - start; i++) {
3203         val = *(data + i);
3204         val = ABS(val);
3205         if (val > maxamp)
3206             maxamp = val;
3207     }
3208 
3209     if (maxamp == 0)
3210         return;
3211 
3212     ground = rint((gfloat)maxamp * pow(10.0, thrshld / 20));
3213 
3214     /* Computing the beginning average level until we reach the ground level */
3215     for (c = 0, ofs = start, amp = 0, avg = 0; ofs < end && amp < ground; ofs++) {
3216         val = *(data + ofs);
3217         if (ofs == start) {
3218             bval = -val;
3219             amp = ABS(val);
3220         }
3221         if ((val < 0 && bval >= 0) || (val >= 0 && bval < 0)) {
3222             avg += amp;
3223             c++;
3224             amp = 0;
3225         } else {
3226             if (ABS(val) > amp)
3227                 amp = ABS(val);
3228         }
3229         bval = val;
3230     }
3231     avg = avg / c;
3232 
3233     /* Locating when sounds turns on.
3234        That is : when we *last* got higher than the average level. */
3235     for (amp = maxamp; ofs > start && amp > avg; --ofs) {
3236         amp = 0;
3237         for (val = 1; ofs > start && val > 0; --ofs) {
3238             val = *(data + ofs);
3239             if (val > amp)
3240                 amp = val;
3241         }
3242         for (; ofs > start && val <= 0; --ofs) {
3243             val = *(data + ofs);
3244             if (-val > amp)
3245                 amp = -val;
3246         }
3247     }
3248     on = ofs;
3249 
3250     /* Computing the ending average level until we reach the ground level */
3251     for (ofs = end - 1, avg = 0, amp = 0, c = 0; ofs > on && amp < ground; ofs--) {
3252         val = *(data + ofs);
3253         if (ofs == end - 1) {
3254             bval = -val;
3255             amp = ABS(val);
3256         }
3257         if ((val < 0 && bval >= 0) || (val >= 0 && bval < 0)) {
3258             avg += amp;
3259             c++;
3260             amp = 0;
3261         } else {
3262             if (ABS(val) > amp)
3263                 amp = ABS(val);
3264         }
3265         bval = val;
3266     }
3267     avg = avg / c;
3268 
3269     /* Locating when sounds turns off.
3270        That is : when we *last* got higher than the average level. */
3271     for (amp = maxamp; ofs < end && amp > avg; ++ofs) {
3272         amp = 0;
3273         for (val = 1; ofs < end && val > 0; ++ofs) {
3274             val = *(data + ofs);
3275             if (val > amp)
3276                 amp = val;
3277         }
3278         for (; ofs < end && val <= 0; ++ofs) {
3279             val = *(data + ofs);
3280             if (-val > amp)
3281                 amp = -val;
3282         }
3283     }
3284     off = ofs;
3285 
3286     // Wiping blanks out
3287     if (on < start)
3288         on = start;
3289     if (off > end)
3290         off = end;
3291     if (!sample_editor_check_and_log_sample(current_sample,
3292         N_("Sample trimming"), HISTORY_FLAG_LOG_ALL, 0))
3293         return;
3294 
3295     sample_editor_lock_sample();
3296     if (trbeg) {
3297         sample_editor_delete(current_sample, start, on);
3298         off -= on - start;
3299         end -= on - start;
3300     }
3301     if (trend)
3302         sample_editor_delete(current_sample, off, end);
3303     st_sample_fix_loop(current_sample);
3304     sample_editor_unlock_sample();
3305 
3306     sample_editor_update();
3307 
3308     if (reselect == 1 && off > on)
3309         sample_display_set_selection(sampledisplay, start, start + off - on);
3310 }
3311 
3312 /* deletes the portion of *sample data from start to end-1 */
3313 static void sample_editor_delete(STSample* sample, int start, int end)
3314 {
3315     int newlen;
3316     gint16* newdata;
3317 
3318     if (sample == NULL || start == -1 || start >= end)
3319         return;
3320 
3321     newlen = sample->sample.length - end + start;
3322 
3323     newdata = malloc(newlen * 2);
3324     if (!newdata)
3325         return;
3326 
3327     memcpy(newdata, sample->sample.data, start * 2);
3328     memcpy(newdata + start, sample->sample.data + end, (sample->sample.length - end) * 2);
3329 
3330     free(sample->sample.data);
3331 
3332     sample->sample.data = newdata;
3333     sample->sample.length = newlen;
3334 
3335     /* Move loop start and end along with splice */
3336     if (sample->sample.loopstart > start && sample->sample.loopend < end) {
3337         /* loop was wholly within selection -- remove it */
3338         sample->sample.looptype = ST_MIXER_SAMPLE_LOOPTYPE_NONE;
3339         sample->sample.loopstart = 0;
3340         sample->sample.loopend = 1;
3341     } else {
3342         if (sample->sample.loopstart > end) {
3343             /* loopstart was after selection */
3344             sample->sample.loopstart -= (end - start);
3345         } else if (sample->sample.loopstart > start) {
3346             /* loopstart was within selection */
3347             sample->sample.loopstart = start;
3348         }
3349 
3350         if (sample->sample.loopend > end) {
3351             /* loopend was after selection */
3352             sample->sample.loopend -= (end - start);
3353         } else if (sample->sample.loopend > start) {
3354             /* loopend was within selection */
3355             sample->sample.loopend = start;
3356         }
3357     }
3358 
3359     st_sample_fix_loop(sample);
3360 }
3361 
3362 GtkAdjustment*
3363 sample_editor_get_adjustment(SampleEditorSpin n)
3364 {
3365     GtkWidget* spn = se_spins[n];
3366 
3367     g_assert(GTK_IS_SPIN_BUTTON(spn));
3368     return gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(spn));
3369 }
3370