1 /*
2  * Copyright (C) 2002 2003 2004 2005 2006 2007 2008 2009 2011, Magnus Hjorth
3  *
4  * This file is part of mhWaveEdit.
5  *
6  * mhWaveEdit 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  * mhWaveEdit 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 mhWaveEdit; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 
22 
23 /* Chunk objects represent a segment of (PCM) audio data. The Chunks gets its
24  * data from one or many Datasource objects.
25  *
26  * The Datasources that constitute the Chunk's data must all have the same
27  * format as the Chunk.
28  *
29  * The Chunks are never modified after they are created, instead all functions
30  * that modify a chunk return a new chunk with the changes, while the original
31  * chunk and its data remains intact.
32  */
33 
34 
35 
36 #ifndef CHUNK_H_INCLUDED
37 #define CHUNK_H_INCLUDED
38 
39 #include <stdio.h>
40 #include <gtk/gtk.h>
41 
42 #ifdef HAVE_LIBSNDFILE
43 #include <sndfile.h>
44 #endif
45 
46 #include "datasource.h"
47 #include "statusbar.h"
48 #include "gtkfiles.h"
49 
50 #define CHUNK(obj) GTK_CHECK_CAST(obj,chunk_get_type(),Chunk)
51 #define CHUNK_CLASS(class) GTK_CHECK_CLASS_CAST(class,chunk_get_type(),ChunkClass)
52 #define IS_CHUNK(obj) GTK_CHECK_TYPE(obj,chunk_get_type())
53 
54 
55 typedef struct _Chunk {
56      GtkObject object;
57 
58      Dataformat format;
59 
60      GList *parts;               /* All items should be of type DataPart */
61 
62      /* These must match the sum of the parts */
63      off_t length;             /*�Number of samples */
64      off_t size;               /* Number of bytes (should always be
65 				* length*format.samplesize*format.channels) */
66 
67      guint opencount;            /* For detecting missing chunk_close calls */
68 
69 } Chunk;
70 
71 typedef struct _ChunkClass {
72 	GtkObjectClass parent;
73 } ChunkClass;
74 
75 
76 typedef struct {
77      Datasource *ds;
78      off_t position;
79      off_t length;
80 } DataPart;
81 
82 
83 /* Data structure used for chunk_open,chunk_read etc. */
84 typedef Chunk ChunkHandle;
85 
86 
87 
88 
89 
90 typedef gpointer WriteoutID;
91 
92 /* Function for outputting processed data
93  *
94  * data - The data to output
95  * length - Length of the data (must be multiples of sample size)
96  *
97  * return value - TRUE on failure, FALSE on success
98  */
99 
100 typedef gboolean (*chunk_writeout_func)(WriteoutID id, gpointer data,
101 					guint length);
102 
103 
104 /* Type for use as callback function for chunk_filter.
105  *
106  * NOTE: These callback functions should not call any other chunk functions
107  * except the chunk_sample_get/put-functions...
108  *
109  *  in - Buffer of input data
110  *  sample_size - The size of the in buffer (0 means EOF)
111  *  out - Function to call for outputting data. If a out function call fails,
112  *    this function should fail as well.
113  *  id - Parameter to send with every call to out.
114  *  format - Format of input and output data.
115  *
116  *  return value - TRUE on failure, FALSE on success
117  */
118 
119 typedef gboolean (*chunk_filter_proc)(void *in, guint sample_size,
120 				      chunk_writeout_func out_func,
121 				      WriteoutID id, Dataformat *format);
122 
123 
124 typedef gboolean (*chunk_filter_tofmt_proc)(void *in, guint sample_size,
125 					    chunk_writeout_func out_func,
126 					    WriteoutID id,
127 					    Dataformat *informat,
128 					    Dataformat *outformat);
129 
130 
131 /* Type for use as callback function for chunk_parse.
132 
133     sample - Buffer of input data
134     sample_size - The size of the in buffer (0 means EOF)
135     chunk - The chunk being processed.
136 
137     return value - Return FALSE to continue parsing, otherwise parsing stops.
138  */
139 
140 typedef gboolean (*chunk_parse_proc)(void *sample,gint sample_size,
141 				     Chunk *chunk);
142 
143 
144 
145 
146 
147 /* Flag that decides whether tempfiles created using chunk_filter
148  * should be floating-point if the processing function outputs
149  * floating-point data. If not, the data will be converted back and
150  * written in the original Chunk's format.
151  */
152 
153 extern gboolean chunk_filter_use_floating_tempfiles;
154 
155 
156 /* ------------------------------ FUNCTIONS --------------------------------- */
157 
158 
159 /* Note: All functions that return gboolean values return FALSE on success. */
160 
161 /* If any function fails, it will display an error message box before it
162  * returns.*/
163 
164 
165 
166 /*  ------ Creation functions ------  */
167 
168 
169 GtkType chunk_get_type(void);
170 Chunk *chunk_new_from_datasource(Datasource *ds);
171 
172 /** Returns a new chunk with the same data as this chunk but assumed to be in a
173  * different sample format.
174  */
175 Chunk *chunk_clone_df(Chunk *chunk, Dataformat *format);
176 
177 
178 
179 
180 /* Creates a silent chunk
181      format - The data format of the chunk.
182      num_samples - The length of the chunk.
183 */
184 
185 #define chunk_new_empty(format,num_samples) chunk_new_from_datasource(datasource_new_silent(format,num_samples))
186 
187 
188 
189 /* Same as chunk_new_empty but you specify length as number of seconds instead
190  * of samples.
191  */
192 
193 Chunk *chunk_new_silent(Dataformat *format, gfloat seconds);
194 
195 
196 
197 /* The number of chunk objects currently in existence */
198 
199 guint chunk_alive_count(void);
200 
201 
202 
203 
204 
205 
206 /*  ------ Saving functions ------ */
207 
208 
209 
210 /* Save a chunk's data into a file.
211 
212      chunk - The chunk to save.
213      file - An opened file handle to save the data into.
214      bigendian - TRUE if dumped PCM data should be big-endian.
215      bar - Status bar to display progress. Must already be in progress mode.
216 */
217 
218 gboolean chunk_dump(Chunk *chunk, EFILE *file, gboolean bigendian,
219 		    int dither_mode, StatusBar *bar);
220 
221 
222 
223 
224 /*  ------ Chunk reading functions. ------ */
225 
226 
227 /* Open a chunk for reading. Returns a ChunkHandle that can be used with
228  * chunk_read and chunk_read_array. The ChunkHandle must be released using
229  * chunk_close.
230  */
231 
232 ChunkHandle *chunk_open(Chunk *chunk);
233 
234 
235 
236 /* Read a raw multi-channel sample from the chunk.
237      handle - ChunkHandle returned by chunk_open.
238      sampleno - The sample to read.
239      buffer - The buffer to read into. Must be at least chunk->samplebytes
240        bytes long. */
241 
242 gboolean chunk_read(ChunkHandle *handle, off_t sampleno, void *buffer,
243 		    int dither_mode);
244 
245 
246 
247 /* Read a floating-point multi-channel sample from the chunk
248      handle - ChunkHandle returned by chunk_open.
249      sampleno - The sample to read.
250      buffer - The buffer to read into. Must be at least channels * sizeof(sample_t)
251        bytes long. */
252 
253 gboolean chunk_read_fp(ChunkHandle *handle, off_t sampleno, sample_t *buffer,
254 		       int dither_mode);
255 
256 
257 
258 /* Read an entire array of samples from the chunk.
259 
260      handle - ChunkHandle returned by chunk_open
261      sampleno - The first sample to read.
262      size - The number of bytes to read. Will be rounded down to whole sample.
263      buffer - The buffer to read into
264 
265      return value - The number of bytes read (0 for error)
266 */
267 
268 guint chunk_read_array(ChunkHandle *handle, off_t sampleno, guint size,
269 		       void *buffer, int dither_mode, off_t *clipcount);
270 
271 
272 
273 /* Read an entire array of floating-point samples from the chunk.
274 
275      handle - ChunkHandle returned by chunk_open
276      sampleno - The first sample to read.
277      samples - The number of multi-channel samples to read
278      buffer - The buffer to read into
279 
280      return value - The number of multi-channel samples read (0 for error)
281 */
282 
283 guint chunk_read_array_fp(ChunkHandle *handle, off_t sampleno, guint samples,
284 			  sample_t *buffer, int dither_mode, off_t *clipcount);
285 
286 
287 /* Frees the resources used by a ChunkHandle. All handles should be freed when
288  * they're no longer in use.
289  */
290 
291 void chunk_close(ChunkHandle *handle);
292 
293 
294 
295 
296 /* ------ Chunk effects and utility functions ------- */
297 
298 /* All these functions return a new (temporary) chunk on success and NULL on
299  * failure */
300 
301 
302 
303 /* Creates a new chunk with the original chunks data converted into a different
304  * sample rate possibly using interpolation. */
305 
306 Chunk *chunk_convert_samplerate(Chunk *chunk, gint samplerate,
307 				const gchar *rateconv_driver,
308 				int dither_mode, StatusBar *bar);
309 
310 Chunk *chunk_convert_speed(Chunk *chunk, gfloat speed_factor,
311 			   int dither_mode, StatusBar *bar);
312 
313 
314 /* Creates a new chunk with the original chunk's data converted into a
315  * different sample format (samplerate and channels are unchanged) */
316 Chunk *chunk_convert_sampletype(Chunk *chunk, Dataformat *newtype);
317 
318 /* Converts the chunk to any format. */
319 Chunk *chunk_convert(Chunk *chunk, Dataformat *new_format,
320 		     int dither_mode, StatusBar *bar);
321 
322 Chunk *chunk_byteswap(Chunk *chunk);
323 
324 /* Creates a new chunk with the original chunk's data but with one channel
325  * removed. */
326 
327 Chunk *chunk_remove_channel(Chunk *chunk, gint channel, StatusBar *bar);
328 
329 
330 
331 /* Creates a new chunk with the original chunk's data but with an extra channel
332  * inserted containing a copy of another channel's data. */
333 
334 Chunk *chunk_copy_channel(Chunk *chunk, gint channel, int dither_mode,
335 			  StatusBar *bar);
336 
337 
338 
339 /* Creates a new chunk with the original chunk's data mixed into one channel. */
340 
341 Chunk *chunk_onechannel(Chunk *chunk, int dither_mode, StatusBar *bar);
342 
343 /* Creates a new Chunk with the original chunk's data, but with the
344  * last channels removed or silent channels added so the channel count
345  * becomes new_channels */
346 Chunk *chunk_convert_channels(Chunk *chunk, guint new_channels);
347 
348 
349 
350 
351 /* Creates a new Chunk with a mix of the original chunk's channels.
352  * channels_out determines the number of output channels
353  * map is a (chunk->channels x channels_out)-matrix;
354  *   If map[src*channels_out + dst], then channel <src> from chunk will be
355  *   copied into channel <dst> of the result. Output channels with no assigned
356  *   inputs will be silent, output channels with more than one assigned input
357  *   will be mixed.
358  */
359 Chunk *chunk_remap_channels(Chunk *chunk, int channels_out, gboolean *map,
360 			    int dither_mode, StatusBar *bar);
361 
362 /* Creates a new chunk containing a mix of two chunk's data. The chunks must
363  * have the same format but need not be of the same length. */
364 
365 Chunk *chunk_mix(Chunk *c1, Chunk *c2, int dither_mode, StatusBar *bar);
366 
367 /* Creates a new Chunk with a channel count of the sum of c1 and c2:s channel
368  * counts, having the data from Chunk c1 in the first channels, and
369  * the data from Chunk c2 in the following channels.
370  *
371  * The data is aligned in time, so that the sample in c1 at
372  * c1_align_point coincides with the sample in c2 at
373  * c2_align_point. The point in the resulting chunk where this sample
374  * exists is stored in *align_point_out.
375  */
376 
377 Chunk *chunk_sandwich(Chunk *c1, Chunk *c2,
378 		      off_t c1_align_point, off_t c2_align_point,
379 		      off_t *align_point_out,
380 		      int dither_mode, StatusBar *bar);
381 
382 
383 off_t chunk_zero_crossing_any_forward(
384   Chunk *c, StatusBar *bar, off_t cursorpos);
385 off_t chunk_zero_crossing_any_reverse(
386   Chunk *c, StatusBar *bar, off_t cursorpos);
387 off_t chunk_zero_crossing_all_forward(
388   Chunk *c, StatusBar *bar, off_t cursorpos);
389 off_t chunk_zero_crossing_all_reverse(
390   Chunk *c, StatusBar *bar, off_t cursorpos);
391 
392 
393 /* Returns the maximum absolute value of all the samples in the chunk.
394  * Returns negative value if anything failed. */
395 
396 sample_t chunk_peak_level(Chunk *c, StatusBar *bar);
397 
398 
399 
400 
401 /* Returns a new chunk with all samples of the chunk c multiplied by a
402  * factor. */
403 
404 Chunk *chunk_amplify(Chunk *c, sample_t factor, int dither_mode,
405 		     StatusBar *bar);
406 
407 
408 
409 /* Creates a new chunk with all samples of the chunk c multiplied by a factor
410  * varying from start_factor to end_factor
411  */
412 Chunk *chunk_volume_ramp(Chunk *c, sample_t start_factor, sample_t end_factor,
413 			 int dither_mode, StatusBar *bar);
414 
415 /* Create a new chunk consisting of one chunk's data followed by another
416  * chunk's data. Always succeeds.
417  */
418 
419 Chunk *chunk_append(Chunk *first, Chunk *second);
420 
421 
422 
423 /* Create a new chunk of the same length and format as the input chunk,
424  * consisting of a linear interpolation between the input chunk's two
425  * endpoints. Returns NULL on failure.
426  *
427  * If falldown_mode is TRUE and the chunk is long, the endpoints will
428  *be ramped down to zero and the middle part will be constant zero.
429  */
430 
431 Chunk *chunk_interpolate_endpoints(Chunk *chunk, gboolean falldown_mode,
432 				   int dither_mode, StatusBar *bar);
433 
434 
435 
436 /* Creates a new chunk with the original chunk's data and another chunk's data
437  * inserted at a certain offset (offset must be at an even sample) */
438 
439 Chunk *chunk_insert(Chunk *chunk, Chunk *part, off_t position);
440 
441 /* Returns a chunk containing a part of the original chunk's data */
442 
443 Chunk *chunk_get_part(Chunk *chunk, off_t start, off_t length);
444 
445 /* These functions return a new chunk where a part of the original chunk's
446  * data has been removed or replaced by the data of another chunk.
447  */
448 
449 Chunk *chunk_remove_part(Chunk *chunk, off_t start, off_t length);
450 Chunk *chunk_replace_part(Chunk *chunk, off_t start, off_t length, Chunk *new);
451 
452 
453 
454 /* ------ Processing functions ------ */
455 
456 
457 /* Pipe a chunk's contents through a callback function and create a new chunk
458  * with the output.
459  *
460  *   chunk - The chunk to process
461  *   proc - The callback function (see declaration of chunk_filter_proc above)
462  *   eof_proc - If this argument is non-NULL, when all data has been filtered
463  *     through proc, this function will be called with sample_size==0 to produce
464  *     the last data. This argument is usually either NULL or the same as proc.
465  *   amount - How much should be sent each time. One of:
466  *     CHUNK_FILTER_ONE - One sample value at a time
467  *     CHUNK_FILTER_FULL - One multichannel sample at a time
468  *     CHUNK_FILTER_MANY - Many multichannel samples at a time. The callback
469  *           function can determine the exact amount by looking at the
470  *            sample_size parameter.
471  *
472  *   must_convert - If TRUE the in and out buffer will always be in
473  *   sample_t format instead of the chunk's native sample format.
474  *   bar - Status bar to display progress in
475  *   title - Title to display in status bar.
476  *   returns - The output or NULL on failure.
477  */
478 
479 #define CHUNK_FILTER_ONE 0
480 #define CHUNK_FILTER_FULL 1
481 #define CHUNK_FILTER_MANY 2
482 
483 Chunk *chunk_filter(Chunk *chunk, chunk_filter_proc proc,
484 		    chunk_filter_proc eof_proc, gint amount,
485 		    gboolean must_convert, int dither_mode,
486 		    StatusBar *bar, gchar *title);
487 
488 Chunk *chunk_filter_tofmt(Chunk *chunk, chunk_filter_tofmt_proc proc,
489 			  chunk_filter_tofmt_proc eof_proc, gint amount,
490 			  gboolean must_convert, Dataformat *tofmt,
491 			  int dither_mode,
492 			  StatusBar *bar, gchar *title);
493 
494 /* Send a chunk's contents one sample at a time to a callback function.
495  *
496  *   chunk - The chunk to process.
497  *   proc - The callback function (see definition of chunk_parse_proc above).
498  *   allchannels - If TRUE the samples will be sent with all channels' data at
499  *     the same time, if FALSE one channel at a time will be sent.
500  *   convert - If TRUE the samples will be sent as sample_t (floating point)
501  *     values, otherwise they will be sent in raw format.
502  *   samplepos - The location within the chunk that parsing should start at.
503  *   reverse - If TRUE, parsing will move backward through the chunk; if FALSE
504  *     parsing will move forward through the chunk.
505  *
506  *   returns - FALSE on success, TRUE if proc returned TRUE or a read error
507  *     occured.
508  */
509 
510 gboolean chunk_parse(Chunk *chunk, chunk_parse_proc proc, gboolean allchannels,
511 		     gboolean convert, int dither_mode,
512 		     StatusBar *bar, gchar *title, off_t samplepos, gboolean reverse);
513 
514 
515 
516 /* ------ Miscellaneous chunk functions ------ */
517 
518 
519 
520 /* Determines whether the format parameters of two chunks are the same.
521  * To return TRUE, the chunks must have the same samplerate, samplesize,
522  * channels and sign. */
523 
524 #define chunk_format_equal(c1,c2) dataformat_equal(&(c1->format),&(c2->format))
525 
526 
527 
528 #define chunk_get_time(c,s,t) get_time((c)->format.samplerate,s,s,t,default_time_mode)
529 
530 
531 
532 /* Calls func for each existing chunk. */
533 void chunk_foreach(GFunc func, gpointer user_data);
534 
535 gboolean clipwarn(off_t clipcount, gboolean maycancel);
536 
537 
538 #endif
539