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 
28 #include <sweep/sweep_i18n.h>
29 #include <sweep/sweep_types.h>
30 #include <sweep/sweep_typeconvert.h>
31 #include <sweep/sweep_undo.h>
32 #include <sweep/sweep_filter.h>
33 #include <sweep/sweep_sounddata.h>
34 #include <sweep/sweep_sample.h>
35 
36 #include "sweep_app.h"
37 #include "edit.h"
38 
39 
40 static void
do_filter_regions(sw_sample * sample,SweepFilterRegion func,sw_param_set pset,gpointer custom_data)41 do_filter_regions (sw_sample * sample, SweepFilterRegion func,
42 		   sw_param_set pset, gpointer custom_data)
43 {
44   sw_sounddata * sounddata = sample->sounddata;
45   sw_format * f = sounddata->format;
46   GList * gl;
47   sw_sel * sel;
48   sw_framecount_t sel_total, run_total;
49   sw_framecount_t offset, remaining, n;
50   gpointer d;
51   gint percent;
52 
53   gboolean active = TRUE;
54 
55   sel_total = sounddata_selection_nr_frames (sounddata) / 100;
56   if (sel_total == 0) sel_total = 1;
57   run_total = 0;
58 
59   for (gl = sounddata->sels; active && gl; gl = gl->next) {
60     sel = (sw_sel *)gl->data;
61 
62     offset = 0;
63     remaining = sel->sel_end - sel->sel_start;
64 
65     while (active && remaining > 0) {
66       g_mutex_lock (sample->ops_mutex);
67 
68       if (sample->edit_state == SWEEP_EDIT_STATE_CANCEL) {
69 	active = FALSE;
70       } else {
71 	d = sounddata->data + (int)frames_to_bytes (f, sel->sel_start + offset);
72 
73 	n = MIN(remaining, 1024);
74 
75 	func (d, sounddata->format, n, pset, custom_data);
76 
77 	remaining -= n;
78 	offset += n;
79 
80 	run_total += n;
81 	percent = run_total / sel_total;
82 	sample_set_progress_percent (sample, percent);
83 
84 #ifdef DEBUG
85 	g_print ("completed %d / %d frames, %d%%\n", run_total, sel_total,
86 		 percent);
87 #endif
88       }
89 
90       g_mutex_unlock (sample->ops_mutex);
91     }
92   }
93 }
94 
95 static void
do_filter_regions_thread(sw_op_instance * inst)96 do_filter_regions_thread (sw_op_instance * inst)
97 {
98   sw_sample * sample = inst->sample;
99   sw_perform_data * pd = (sw_perform_data *)inst->do_data;
100 
101   sw_edit_buffer * old_eb;
102   paste_over_data * p;
103 
104   if (sample == NULL || sample->sounddata == NULL ||
105       sample->sounddata->sels == NULL) goto noop;
106 
107   old_eb = edit_buffer_from_sample (sample);
108 
109   p = paste_over_data_new (old_eb, old_eb);
110   inst->redo_data = inst->undo_data = p;
111   set_active_op (sample, inst);
112 
113   do_filter_regions (sample, (SweepFilterRegion)pd->func, pd->pset,
114 		     pd->custom_data);
115 
116   if (sample->edit_state == SWEEP_EDIT_STATE_BUSY) {
117     p->new_eb = edit_buffer_from_sample (sample);
118 
119     register_operation (sample, inst);
120   }
121 
122   return;
123 
124  noop:
125   sample_set_tmp_message (sample, _("No selection to process"));
126 }
127 
128 static sw_operation filter_regions_op = {
129   SWEEP_EDIT_MODE_FILTER,
130   (SweepCallback)do_filter_regions_thread,
131   (SweepFunction)g_free,
132   (SweepCallback)undo_by_paste_over,
133   (SweepFunction)paste_over_data_destroy,
134   (SweepCallback)redo_by_paste_over,
135   (SweepFunction)paste_over_data_destroy
136 };
137 
138 sw_op_instance *
perform_filter_region_op(sw_sample * sample,char * desc,SweepFilterRegion func,sw_param_set pset,gpointer custom_data)139 perform_filter_region_op (sw_sample * sample, char * desc,
140 			  SweepFilterRegion func,
141 			  sw_param_set pset, gpointer custom_data)
142 {
143   sw_perform_data * pd = (sw_perform_data *)g_malloc (sizeof(*pd));
144 
145   pd->func = (SweepFunction)func;
146   pd->pset = pset;
147   pd->custom_data = custom_data;
148 
149   schedule_operation (sample, desc, &filter_regions_op, pd);
150 
151   return NULL;
152 }
153 
154 static void
do_filter_thread(sw_op_instance * inst)155 do_filter_thread (sw_op_instance * inst)
156 {
157   sw_sample * sample = inst->sample;
158   sw_perform_data * pd = (sw_perform_data *)inst->do_data;
159 
160   SweepFilter func = (SweepFilter)pd->func;
161   sw_param_set pset = pd->pset;
162   void * custom_data = pd->custom_data;
163 
164   sw_edit_buffer * old_eb;
165   paste_over_data * p;
166   sw_sample * out;
167 
168   old_eb = edit_buffer_from_sample (sample);
169 
170   p = paste_over_data_new (old_eb, old_eb);
171   inst->redo_data = inst->undo_data = p;
172   set_active_op (sample, inst);
173 
174   out = func (sample, pset, custom_data);
175 
176   /* XXX: this is all kinda assuming out == sample if out != NULL */
177   if (out != NULL && sample->edit_state == SWEEP_EDIT_STATE_BUSY) {
178     p->new_eb = edit_buffer_from_sample (sample);
179 
180     register_operation (sample, inst);
181   }
182 }
183 
184 static sw_operation filter_op = {
185   SWEEP_EDIT_MODE_FILTER,
186   (SweepCallback)do_filter_thread,
187   (SweepFunction)g_free,
188   (SweepCallback)undo_by_paste_over,
189   (SweepFunction)paste_over_data_destroy,
190   (SweepCallback)redo_by_paste_over,
191   (SweepFunction)paste_over_data_destroy
192 };
193 
194 
195 sw_op_instance *
perform_filter_op(sw_sample * sample,char * desc,SweepFilter func,sw_param_set pset,gpointer custom_data)196 perform_filter_op (sw_sample * sample, char * desc, SweepFilter func,
197 		   sw_param_set pset, gpointer custom_data)
198 {
199   sw_perform_data * pd = (sw_perform_data *)g_malloc (sizeof(*pd));
200 
201   pd->func = (SweepFunction)func;
202   pd->pset = pset;
203   pd->custom_data = custom_data;
204 
205   schedule_operation (sample, desc, &filter_op, pd);
206 
207   return NULL;
208 }
209