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(¤t_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(¤t_sample->sample);
198 }
199 g_mutex_unlock(¤t_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 = ¤t_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 == ¤t_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(©buffer_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 ¤t_sample->relnote,
1843 ¤t_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 ¤t_sample->relnote,
2849 ¤t_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 = ¤t_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