1 /*
2  * Sweep, a sound wave editor.
3  *
4  * Copyright (C) 2000 Conrad Parker
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24 
25 #include <stdio.h>
26 #include <string.h>
27 #include <glib.h>
28 
29 #if 0
30 #include <unistd.h>
31 #include <sys/mman.h>
32 #endif
33 
34 #include <sweep/sweep_types.h>
35 #include <sweep/sweep_typeconvert.h>
36 #include <sweep/sweep_selection.h>
37 #include <sweep/sweep_undo.h>
38 
39 #include "edit.h"
40 #include "format.h"
41 #include "view.h"
42 #include "sample-display.h"
43 #include "driver.h"
44 
45 sw_sounddata *
sounddata_new_empty(gint nr_channels,gint sample_rate,gint sample_length)46 sounddata_new_empty(gint nr_channels, gint sample_rate, gint sample_length)
47 {
48   sw_sounddata *s;
49   sw_framecount_t len;
50 
51   s = g_malloc (sizeof(sw_sounddata));
52   if (!s)
53     return NULL;
54 
55   s->refcount = 1;
56 
57   s->format = format_new (nr_channels, sample_rate);
58 
59   s->nr_frames = (sw_framecount_t) sample_length;
60 
61   if (sample_length > 0) {
62     len = frames_to_bytes (s->format, sample_length);
63 
64 #if 1
65     s->data = g_malloc0 ((size_t)len);
66 #else
67     s->data = sweep_large_alloc_zero (len, PROT_READ|PROT_WRITE);
68 #endif
69 
70 
71     if (!(s->data)) {
72 #if 0
73 #if (SIZEOF_OFF_T == 8)
74       fprintf(stderr, "Unable to allocate %lld bytes for sample data.\n", len);
75 #else
76       fprintf(stderr, "Unable to allocate %d bytes for sample data.\n", len);
77 #endif
78 #else
79       fprintf(stderr, "Unable to allocate %d bytes for sample data.\n", len);
80 #endif
81       g_free(s);
82       return NULL;
83 #ifdef DEBUG
84     } else {
85       g_print ("g_malloc0'd %d bytes for new sounddata\n", len);
86 #endif
87     }
88   } else {
89     s->data = NULL;
90   }
91 
92   s->sels = NULL;
93   s->sels_mutex = g_mutex_new();
94   s->data_mutex = g_mutex_new();
95 
96   return s;
97 }
98 
99 void
sounddata_clear_selection(sw_sounddata * sounddata)100 sounddata_clear_selection (sw_sounddata * sounddata)
101 {
102   GList * gl;
103   sw_sel * sel;
104 
105   for (gl = sounddata->sels; gl; gl = gl->next){
106           sel = (sw_sel*)gl->data;
107           sel_free(sel);
108   }
109 
110   g_list_free(sounddata->sels);
111 
112   sounddata->sels = NULL;
113 };
114 
115 void
sounddata_destroy(sw_sounddata * sounddata)116 sounddata_destroy (sw_sounddata * sounddata)
117 {
118   /*size_t len;*/
119 
120   sounddata->refcount--;
121 
122   if (sounddata->refcount <= 0) {
123 #if 1
124     g_free (sounddata->data);
125 #else
126     len = frames_to_bytes (sounddata->format, sounddata->nr_frames);
127     munmap (sounddata->data, len);
128 #endif
129     sounddata_clear_selection (sounddata);
130     g_free (sounddata);
131     g_mutex_free(sounddata->data_mutex);
132   }
133 }
134 
135 void
sounddata_lock_selection(sw_sounddata * sounddata)136 sounddata_lock_selection (sw_sounddata * sounddata)
137 {
138   g_mutex_lock (sounddata->sels_mutex);
139 }
140 
141 void
sounddata_unlock_selection(sw_sounddata * sounddata)142 sounddata_unlock_selection (sw_sounddata * sounddata)
143 {
144   g_mutex_unlock (sounddata->sels_mutex);
145 }
146 
147 guint
sounddata_selection_nr_regions(sw_sounddata * sounddata)148 sounddata_selection_nr_regions (sw_sounddata * sounddata)
149 {
150   return g_list_length (sounddata->sels);
151 }
152 
153 static gint
sounddata_sel_needs_normalising(sw_sounddata * sounddata)154 sounddata_sel_needs_normalising (sw_sounddata *sounddata)
155 {
156   GList * gl;
157   sw_sel * osel = NULL, * sel;
158   sw_framecount_t nr_frames;
159 
160   if(!sounddata->sels) return FALSE;
161 
162   nr_frames = sounddata->nr_frames;
163 
164   /* Seed osel with 'fake' iteration of following loop */
165   gl = sounddata->sels;
166   osel = (sw_sel *)gl->data;
167   if (osel->sel_start < 0 || osel->sel_end > nr_frames)
168     return TRUE;
169 
170   gl = gl->next;
171   for(; gl; gl = gl->next) {
172     sel = (sw_sel *)gl->data;
173 
174     if (sel->sel_start < 0 || sel->sel_end > nr_frames)
175       return TRUE;
176 
177     if(osel->sel_end >= sel->sel_start) {
178       return TRUE;
179     }
180 
181     if(osel->sel_end < sel->sel_end) {
182       osel = sel;
183     }
184   }
185 
186   return FALSE;
187 }
188 
189 /*
190  * sounddata_normalise_selection(sounddata)
191  *
192  * normalise the selection of sounddata, ie. make sure there's
193  * no overlaps and merge adjoining sections.
194  */
195 
196 void
sounddata_normalise_selection(sw_sounddata * sounddata)197 sounddata_normalise_selection (sw_sounddata * sounddata)
198 {
199   GList * gl;
200   GList * nsels = NULL;
201   sw_sel * osel = NULL, * sel;
202   sw_framecount_t nr_frames;
203 
204   if (!sounddata_sel_needs_normalising(sounddata)) return;
205 
206   nr_frames = sounddata->nr_frames;
207 
208   /* Seed osel with 'fake' iteration of following loop */
209   gl = sounddata->sels;
210   sel = (sw_sel *)gl->data;
211   sel->sel_start = CLAMP(sel->sel_start, 0, nr_frames);
212   sel->sel_end = CLAMP(sel->sel_end, 0, nr_frames);
213 
214   osel = sel_copy(sel);
215 
216   gl = gl->next;
217 
218   for (; gl; gl = gl->next) {
219     sel = (sw_sel *)gl->data;
220     sel->sel_start = CLAMP(sel->sel_start, 0, nr_frames);
221     sel->sel_end = CLAMP(sel->sel_end, 0, nr_frames);
222 
223     /* Check for an overlap */
224     if(osel->sel_end >= sel->sel_start) {
225 
226       /* If sel is completely contained in osel, ignore it. */
227       if(osel->sel_end > sel->sel_end) {
228 	continue;
229       }
230 
231       /* Set: osel = osel INTERSECT sel
232        * we already know osel->sel_start <= sel->sel_start */
233       osel->sel_end = sel->sel_end;
234 
235     } else {
236       /* No more overlaps with osel; insert it in nsels, and
237        * reset osel. */
238       if (osel->sel_start == osel->sel_end) {
239 	g_free (osel);
240       } else {
241 	nsels = g_list_insert_sorted(nsels, osel, (GCompareFunc)sel_cmp);
242       }
243       osel = sel_copy(sel);
244     }
245   }
246 
247   /* Insert the last created osel */
248   if (osel->sel_start == osel->sel_end) {
249     g_free (osel);
250   } else {
251     nsels = g_list_insert_sorted(nsels, osel, (GCompareFunc)sel_cmp);
252   }
253 
254   /* Clear the old selection */
255   sounddata_clear_selection (sounddata);
256 
257   /* Set the newly created (normalised) selection */
258   sounddata->sels = nsels;
259 
260 }
261 
262 void
sounddata_add_selection(sw_sounddata * sounddata,sw_sel * sel)263 sounddata_add_selection (sw_sounddata * sounddata, sw_sel * sel)
264 {
265   sounddata->sels =
266     g_list_insert_sorted(sounddata->sels, sel, (GCompareFunc)sel_cmp);
267 }
268 
269 sw_sel *
sounddata_add_selection_1(sw_sounddata * sounddata,sw_framecount_t start,sw_framecount_t end)270 sounddata_add_selection_1 (sw_sounddata * sounddata, sw_framecount_t start, sw_framecount_t end)
271 {
272   sw_sel * sel;
273 
274   sel = sel_new (start, end);
275 
276   sounddata_add_selection(sounddata, sel);
277 
278   return sel;
279 }
280 
281 sw_sel *
sounddata_set_selection_1(sw_sounddata * sounddata,sw_framecount_t start,sw_framecount_t end)282 sounddata_set_selection_1 (sw_sounddata * sounddata, sw_framecount_t start, sw_framecount_t end)
283 {
284   sounddata_clear_selection (sounddata);
285 
286   return sounddata_add_selection_1 (sounddata, start, end);
287 }
288 
289 gint
sounddata_selection_nr_frames(sw_sounddata * sounddata)290 sounddata_selection_nr_frames (sw_sounddata * sounddata)
291 {
292   gint nr_frames = 0;
293   GList * gl;
294   sw_sel * sel;
295 
296   for (gl = sounddata->sels; gl; gl = gl->next) {
297     sel = (sw_sel *)gl->data;
298 
299     nr_frames += sel->sel_end - sel->sel_start;
300   }
301 
302   return nr_frames;
303 }
304 
305 sw_framecount_t
sounddata_selection_width(sw_sounddata * sounddata)306 sounddata_selection_width (sw_sounddata * sounddata)
307 {
308   GList * gl;
309   sw_sel * sel;
310   sw_framecount_t start, end;
311 
312   if ((gl = sounddata->sels) == NULL) return 0;
313   sel = (sw_sel *)gl->data;
314   start = sel->sel_start;
315 
316   gl = g_list_last (sounddata->sels);
317   sel = (sw_sel *)gl->data;
318   end = sel->sel_end;
319 
320   return (end - start);
321 }
322 
323 void
sounddata_selection_translate(sw_sounddata * sounddata,gint delta)324 sounddata_selection_translate (sw_sounddata * sounddata, gint delta)
325 {
326   GList * gl;
327   sw_sel * sel;
328 
329   for (gl = sounddata->sels; gl; gl = gl->next) {
330     sel = (sw_sel *)gl->data;
331 
332     sel->sel_start += delta;
333     sel->sel_end += delta;
334   }
335 
336   /* XXX: Crop any regions outside of [0, nr_frames] */
337   sounddata_normalise_selection (sounddata);
338 }
339 
340 void
sounddata_selection_scale(sw_sounddata * sounddata,gfloat scale)341 sounddata_selection_scale (sw_sounddata * sounddata, gfloat scale)
342 {
343   GList * gl;
344   sw_sel * sel;
345   sw_framecount_t sels_start;
346 
347   if ((gl = sounddata->sels) == NULL) return;
348 
349   sel = (sw_sel *)gl->data;
350   sels_start = sel->sel_start;
351 
352   for (gl = sounddata->sels; gl; gl = gl->next) {
353     sel = (sw_sel *)gl->data;
354 
355     sel->sel_start = sels_start + ((sel->sel_start - sels_start) * scale);
356     sel->sel_end = sels_start + ((sel->sel_end - sels_start) * scale);
357   }
358 
359   /* XXX: Crop any regions outside of [0, nr_frames] */
360   sounddata_normalise_selection (sounddata);
361 }
362 
363 /*
364  * sounddata_copyin_selection (sounddata1, sounddata2)
365  *
366  * copies the selection of sounddata1 into sounddata2. If sounddata2 previously
367  * had a selection, the two are merged.
368  */
369 void
sounddata_copyin_selection(sw_sounddata * sounddata1,sw_sounddata * sounddata2)370 sounddata_copyin_selection (sw_sounddata * sounddata1, sw_sounddata * sounddata2)
371 {
372   GList * gl;
373   sw_sel * sel, *sel2;
374 
375   for (gl = sounddata1->sels; gl; gl = gl->next) {
376     sel = (sw_sel *)gl->data;
377 
378     sel2 = sel_copy (sel);
379     sounddata_add_selection (sounddata2, sel2);
380   }
381 
382   sounddata_normalise_selection (sounddata2);
383 }
384