marlin r1357 - in trunk: marlin po src



Author: iain
Date: Mon Feb 16 00:55:24 2009
New Revision: 1357
URL: http://svn.gnome.org/viewvc/marlin?rev=1357&view=rev

Log:
Squashed commit of the following:

commit 41826f5da3e88cc5641361caf97376cc5f6bd3db
Author: Iain Holmes <iain openedhand com mailto:iain openedhand com>
Date:   Mon Feb 16 00:53:17 2009 +0000

    Set the Normalize menu item name correctly, depending on whether or not
     there is a selection

commit 6e37e5cc36d72934ec4613b30607e6f3e19a41ab
Author: Iain Holmes <iain openedhand com mailto:iain openedhand com>
Date:   Mon Feb 16 00:51:23 2009 +0000

    Add the normalize menu item and hook it up

commit fd35e4d37e5d339ecd763f8eb9b2a7792c24a3f6
Author: Iain Holmes <iain openedhand com mailto:iain openedhand com>
Date:   Mon Feb 16 00:29:27 2009 +0000

    Fix some problems with marlin_channel_normalize and add MarlinSample function

commit feac65b4d642543ff606b5fbf8e16c373bc36cab
Author: Iain Holmes <iain openedhand com mailto:iain openedhand com>
Date:   Sun Feb 15 23:04:44 2009 +0000

    Add a normal channel function

Modified:
   trunk/marlin/marlin-channel.c
   trunk/marlin/marlin-channel.h
   trunk/marlin/marlin-sample.c
   trunk/marlin/marlin-sample.h
   trunk/po/Makefile.in.in
   trunk/src/marlin-window-menu.c
   trunk/src/marlin-window.c
   trunk/src/marlin.xml

Modified: trunk/marlin/marlin-channel.c
==============================================================================
--- trunk/marlin/marlin-channel.c	(original)
+++ trunk/marlin/marlin-channel.c	Mon Feb 16 00:55:24 2009
@@ -2,7 +2,7 @@
 /*
  *  Authors: Iain Holmes <iain gnome org>
  *
- *  Copyright 2002-2007 Iain Holmes
+ *  Copyright 2002-2009 Iain Holmes
  *
  *  This file is free software; you can redistribute it and/or
  *  modify it under the terms of version 2 of the GNU Library General Public
@@ -71,7 +71,7 @@
  * sample:
  * filename:
  * error:
- * 
+ *
  * Creates a new channel for @sample, using @filename as the basename for its
  * temp files.
  *
@@ -83,16 +83,16 @@
 {
 	MarlinChannel *channel;
 	char *basename, *name;
-	
+
 	channel = g_new0 (MarlinChannel, 1);
 	channel->lock = marlin_read_write_lock_new ();
 
 	basename = g_path_get_basename (filename);
 	name = g_strdup_printf ("%s/%s.XXXXXX",
-				marlin_get_tmp_dir (), 
+				marlin_get_tmp_dir (),
 				basename);
 	g_free (basename);
-	
+
 	channel->frame_file = marlin_file_new (name, error);
 	g_free (name);
 
@@ -104,10 +104,10 @@
 	basename = g_path_get_basename (channel->frame_file->filename);
 
 	name = g_strdup_printf ("%s/%s.XXXXXX",
-				marlin_get_tmp_dir (), 
+				marlin_get_tmp_dir (),
 				basename);
 	g_free (basename);
-		
+
 	channel->peak_file = marlin_file_new (name, error);
 	g_free (name);
 
@@ -154,7 +154,7 @@
 
 	WRITE_UNLOCK (channel->lock);
 	marlin_read_write_lock_destroy (channel->lock);
-	
+
 	g_free (channel);
 }
 
@@ -169,14 +169,14 @@
 MarlinBlock *
 marlin_channel_create_block (MarlinChannel *channel)
 {
-	return marlin_block_new (channel, channel->frame_file, 
+	return marlin_block_new (channel, channel->frame_file,
 				 channel->peak_file);
 }
 
 /* Implements an LRU paging system */
 /* Max number of blocks that can be mapped for each channel
    Each page is about 2meg of data */
-#define MAX_PAGE_COUNT 10 
+#define MAX_PAGE_COUNT 10
 
 /* define this to turn off the paging system to simplify testing
    of the block/channel manipulation code. */
@@ -189,7 +189,7 @@
  *
  * Adds @block to the LRU cache for @channel or if it is already in
  * the cache it is moved to the start of the queue. If there isn't room
- * in the cache then the block at the end of the queue is removed and 
+ * in the cache then the block at the end of the queue is removed and
  * unmapped.
  *
  * The channel must be write locked.
@@ -226,7 +226,7 @@
 			goto try_again;
 		}
 	}
-	
+
 	g_queue_push_head (channel->pages, block);
 #endif
 	marlin_block_map (block, NULL);
@@ -293,7 +293,7 @@
 
 		b = channel->last;
 		READ_UNLOCK (channel->lock);
-		
+
 		return b;
 	}
 
@@ -305,11 +305,11 @@
 
 		return b;
 	}
-	
+
 	block = lockless_get_for_frame (channel->first, frame);
 
 	READ_UNLOCK (channel->lock);
-		
+
 	return block;
 }
 
@@ -333,7 +333,7 @@
 
 	first = lockless_get_for_frame (channel->first, split_frame);
 	g_return_if_fail (first != NULL);
-	
+
 	if (split_frame != first->start) {
 
 		second = marlin_block_split (first, split_frame);
@@ -343,7 +343,7 @@
 			first->next = second;
 			second->previous = first;
 			second->next = NULL;
-			
+
 			/* If first->next was NULL,
 			   then first was the last block
 			   Set the channel last point to second */
@@ -369,7 +369,7 @@
 			    guint64        split_frame)
 {
 	g_return_if_fail (channel != NULL);
-	
+
 	WRITE_LOCK (channel->lock);
 	lockless_split_block (channel, split_frame);
 	WRITE_UNLOCK (channel->lock);
@@ -428,7 +428,7 @@
 {
 	struct _unlink_closure *c = data;
 	MarlinBlock *b;
-	
+
 	WRITE_LOCK (c->channel->lock);
 	lockless_unlink_range (c->channel, c->start_frame, c->end_frame,
 			       &b, NULL);
@@ -760,7 +760,7 @@
 }
 
 /* Splits the block on the insert_frame, so insert_frame will be first in
-   new block. Then it gets the block for insert_frame - 1, and then inserts 
+   new block. Then it gets the block for insert_frame - 1, and then inserts
    data */
 static gboolean
 lockless_insert_data (MarlinChannel     *channel,
@@ -1489,6 +1489,8 @@
 	return ret;
 }
 
+/* FIXME: Might be useful to have a fixed ratio version so that we don't
+   have to make functions that just return the same number all the time */
 static gboolean
 lockless_channel_multiply (MarlinChannel     *channel,
 			   guint64            start,
@@ -1567,11 +1569,11 @@
  * Returns: TRUE on success, FALSE on failure with details in @error.
  */
 gboolean
-marlin_channel_invert (MarlinChannel *channel,
-		       guint64 start,
-		       guint64 finish,
+marlin_channel_invert (MarlinChannel     *channel,
+		       guint64            start,
+		       guint64            finish,
 		       MarlinUndoContext *ctxt,
-		       GError **error)
+		       GError           **error)
 {
 	gboolean ret;
 	g_return_val_if_fail (channel != NULL, FALSE);
@@ -1660,14 +1662,14 @@
  * Returns: TRUE on success, FALSE on failure with details in @error.
  */
 gboolean
-marlin_channel_fade (MarlinChannel *channel,
-		     guint64 start,
-		     guint64 finish,
-		     MarlinFadeFunc fade_func,
-		     gpointer closure,
-		     MarlinOperation *operation,
+marlin_channel_fade (MarlinChannel     *channel,
+		     guint64            start,
+		     guint64            finish,
+		     MarlinFadeFunc     fade_func,
+		     gpointer           closure,
+		     MarlinOperation   *operation,
 		     MarlinUndoContext *ctxt,
-		     GError **error)
+		     GError           **error)
 {
 	gboolean ret;
 
@@ -1744,9 +1746,9 @@
 	frames_needed = (src_range->finish - src_range->start) + 1;
 
 	src_block = lockless_get_for_frame (src->first, src_range->start);
-	
+
 	/* Unlink all the blocks in dest we're going to replace */
-	lockless_unlink_range (dest, dest_range->start, dest_range->finish, 
+	lockless_unlink_range (dest, dest_range->start, dest_range->finish,
 			       &dest_block, ctxt);
 	d = dest_block;
 
@@ -1767,11 +1769,11 @@
 
 		frames_avail = MIN (frames_needed, MARLIN_BLOCK_SIZE);
 		s_length = marlin_block_get_buffer (src_block, src_buf,
-						    src_start, 
+						    src_start,
 						    frames_avail,
 						    &s_next);
 		if (dest_block != NULL) {
-			d_length = marlin_block_get_buffer (dest_block, 
+			d_length = marlin_block_get_buffer (dest_block,
 							    dest_buf,
 							    dest_start,
 							    frames_avail,
@@ -1782,10 +1784,10 @@
 
 		/* Apply the fades to the buffers */
 		for (i = 0; i < s_length; i++) {
-			src_buf[i] = src_buf[i] * src_fade_func 
+			src_buf[i] = src_buf[i] * src_fade_func
 				(frame_start + i, src_closure);
 			if (i < d_length) {
-				dest_buf[i] = dest_buf[i] * dest_fade_func 
+				dest_buf[i] = dest_buf[i] * dest_fade_func
 					(frame_start + i, dest_closure);
 			}
 
@@ -1849,7 +1851,7 @@
  */
 guint64
 marlin_channel_next_zero (MarlinChannel *channel,
-			  guint64 position)
+			  guint64        position)
 {
 	MarlinBlock *block;
 	float *data;
@@ -2304,3 +2306,91 @@
 
 	return ret;
 }
+
+struct _normalize_closure {
+	float ratio;
+};
+
+static float
+normalize_func (guint64 position,
+		gpointer data)
+{
+	struct _normalize_closure *vc = data;
+	return vc->ratio;
+}
+
+gboolean
+marlin_channel_normalize (MarlinChannel     *channel,
+			  MarlinRange       *range,
+			  double             db,
+			  MarlinOperation   *operation,
+			  MarlinUndoContext *ctxt,
+			  GError           **error)
+{
+	struct _normalize_closure *nc;
+	double max_peak = 0.0;
+	double level = 1.0;
+	guint64 peak_range;
+	MarlinBlock *block;
+	MarlinPeak *peak_data;
+	guint64 start, end;
+	guint64 i, o;
+	float *buf;
+	gboolean ret = FALSE;
+
+	WRITE_LOCK (channel->lock);
+
+	block = lockless_get_for_frame (channel->first, range->start);
+	READ_LOCK (block->lock);
+
+	peak_data = marlin_block_get_peak_data (block);
+
+	start = range->start / MARLIN_FRAMES_PER_PEAK;
+	end = range->finish / MARLIN_FRAMES_PER_PEAK;
+	peak_range = start - end;
+
+	for (i = 0, o = start; i < peak_range; i++, o++) {
+		guint64 peak_in_channel;
+		MarlinPeak p;
+
+		peak_in_channel = block->start + (o * MARLIN_FRAMES_PER_PEAK);
+		if (peak_in_channel >= channel->frames) {
+			break;
+		}
+
+		if (peak_in_channel > block->end) {
+			/* Next block */
+			READ_UNLOCK (block->lock);
+
+			block = marlin_block_next (block);
+			g_assert (block != NULL);
+
+			READ_LOCK (block->lock);
+			o = 0;
+			peak_data = marlin_block_get_peak_data (block);
+		}
+
+		p = peak_data[o];
+
+		max_peak = MAX (max_peak, ((double) p.high / 256.0));
+	}
+
+	READ_UNLOCK (block->lock);
+
+	if (db == MARLIN_INFINITE_DB) {
+		level = 0.0;
+	} else {
+		level = pow (10.0, db / 10.0);
+	}
+
+	nc = g_new (struct _normalize_closure, 1);
+	nc->ratio = level / max_peak;
+
+	ret = lockless_channel_multiply (channel, range->start, range->finish,
+					 normalize_func, nc, ctxt, error);
+	g_free (nc);
+
+	WRITE_UNLOCK (channel->lock);
+
+	return ret;
+}

Modified: trunk/marlin/marlin-channel.h
==============================================================================
--- trunk/marlin/marlin-channel.h	(original)
+++ trunk/marlin/marlin-channel.h	Mon Feb 16 00:55:24 2009
@@ -202,4 +202,10 @@
 
 gboolean marlin_channel_is_ready (MarlinChannel *channel);
 
+gboolean marlin_channel_normalize (MarlinChannel     *channel,
+				   MarlinRange       *range,
+				   double             db,
+				   MarlinOperation   *operation,
+				   MarlinUndoContext *ctxt,
+				   GError           **error);
 #endif

Modified: trunk/marlin/marlin-sample.c
==============================================================================
--- trunk/marlin/marlin-sample.c	(original)
+++ trunk/marlin/marlin-sample.c	Mon Feb 16 00:55:24 2009
@@ -1487,7 +1487,7 @@
 	marlin_undo_context_add (ctxt, u);
 
 	WRITE_LOCK (sample->priv->lock);
-	
+
 	switch (range->coverage) {
 	case MARLIN_COVERAGE_BOTH:
 		for (i = 0; i < sample->priv->channels; i++) {
@@ -1501,7 +1501,7 @@
 
 	case MARLIN_COVERAGE_LEFT:
 		ret = marlin_channel_invert (sample->priv->channel_data->pdata[0],
-					     range->start, range->finish, 
+					     range->start, range->finish,
 					     ctxt, error);
 		if (ret == FALSE) {
 			WRITE_UNLOCK (sample->priv->lock);
@@ -1517,7 +1517,7 @@
 			return FALSE;
 		}
 		ret = marlin_channel_invert (sample->priv->channel_data->pdata[1],
-					     range->start, range->finish, 
+					     range->start, range->finish,
 					     ctxt, error);
 		if (ret == FALSE) {
 			WRITE_UNLOCK (sample->priv->lock);
@@ -1545,7 +1545,7 @@
 	struct _sample_closure *c = data;
 
 	g_object_set (G_OBJECT (c->sample),
-		      "dirty", TRUE, 
+		      "dirty", TRUE,
 		      NULL);
 	marlin_sample_data_changed (c->sample, &(c->range));
 }
@@ -1592,7 +1592,7 @@
 				 adjust_volume_undo,
 				 adjust_volume_destroy,
 				 c);
-	
+
 	marlin_undo_context_add (ctxt, u);
 
 	WRITE_LOCK (sample->priv->lock);
@@ -1627,7 +1627,7 @@
 		}
 
 		ret = marlin_channel_adjust_volume (sample->priv->channel_data->pdata[1], db, range->start, range->finish, ctxt, error);
-		
+
 		if (ret == FALSE) {
 			WRITE_UNLOCK (sample->priv->lock);
 			return FALSE;
@@ -1714,7 +1714,7 @@
 
 	for (i = 0; i < sample->priv->channels; i++) {
 		ret = marlin_channel_insert_silence (sample->priv->channel_data->pdata[i],
-						     operation, position, 
+						     operation, position,
 						     length, ctxt, error);
 		if (ret == FALSE) {
 			WRITE_UNLOCK (sample->priv->lock);
@@ -1763,13 +1763,14 @@
 
 	/* The newly added channel is always the second one */
 	channel = c->sample->priv->channel_data->pdata[1];
-	ret = marlin_channel_copy_data (c->channel, channel, 0, c->channel->frames - 1, NULL);
+	ret = marlin_channel_copy_data (c->channel, channel, 0,
+					c->channel->frames - 1, NULL);
 	if (ret == FALSE) {
 		g_warning ("marlin_channel_copy_data failed");
 	}
 
 	g_object_set (G_OBJECT (c->sample),
-		      "dirty", TRUE, 
+		      "dirty", TRUE,
 		      NULL);
 }
 
@@ -1978,8 +1979,8 @@
 		src = sample->priv->channel_data->pdata[MARLIN_CHANNEL_LEFT];
 
 		/* Fill the new channel with 0 data */
-		ret = marlin_channel_insert_silence (sample->priv->channel_data->pdata[MARLIN_CHANNEL_RIGHT], 
-						     operation, (guint64) 0, 
+		ret = marlin_channel_insert_silence (sample->priv->channel_data->pdata[MARLIN_CHANNEL_RIGHT],
+						     operation, (guint64) 0,
 						     src->frames, NULL, error);
 		if (ret == FALSE) {
 			WRITE_UNLOCK (sample->priv->lock);
@@ -1996,10 +1997,10 @@
 		}
 	} else {
 		MarlinChannel *src, *dest;
-		
+
 		src = sample->priv->channel_data->pdata[MARLIN_CHANNEL_LEFT];
 		dest = sample->priv->channel_data->pdata[MARLIN_CHANNEL_RIGHT];
-		
+
 		ret = marlin_channel_copy_data (src, dest, (guint64) 0, src->frames - 1, error);
 
 		WRITE_UNLOCK (sample->priv->lock);
@@ -2053,7 +2054,7 @@
  *
  * Splits @sample into many smaller #MarlinSample objects with the ranges of
  * these samples taken from marker positions of @sample.
- * 
+ *
  * Return value: A GList containing #MarlinSamples.
  */
 GList *
@@ -2081,7 +2082,7 @@
 			g_warning ("marlin_sample_new_from_sample_with_range failed");
 			return NULL;
 		}
-		
+
 		samples = g_list_prepend (samples, ns);
 
 		g_object_set (G_OBJECT (ns),
@@ -2134,7 +2135,7 @@
 	} else {
 		float m;
 
-		/* 
+		/*
 		   y = mx+c
 		   x = (position - fade_start)
 		   c = fade->in_level
@@ -2180,7 +2181,7 @@
 	int i;
 
 	g_return_val_if_fail (IS_MARLIN_SAMPLE (sample), FALSE);
-	
+
 	c = g_new (struct _sample_closure, 1);
 	c->sample = sample;
 	c->range.start = fade->fade_start;
@@ -2194,11 +2195,11 @@
 	marlin_undo_context_add (ctxt, u);
 
 	WRITE_LOCK (sample->priv->lock);
-	
+
 	for (i = 0; i < sample->priv->channels; i++) {
 		ret = marlin_channel_fade (sample->priv->channel_data->pdata[i],
 					   fade->fade_start, fade->fade_end,
-					   (MarlinFadeFunc) sample_fade_func, 
+					   (MarlinFadeFunc) sample_fade_func,
 					   fade, operation, ctxt, error);
 		if (ret == FALSE) {
 			WRITE_UNLOCK (sample->priv->lock);
@@ -2208,7 +2209,7 @@
 
 	WRITE_UNLOCK (sample->priv->lock);
 	g_object_set (G_OBJECT (sample),
-		      "dirty", TRUE, 
+		      "dirty", TRUE,
 		      NULL);
 
 	marlin_sample_data_changed (sample, &c->range);
@@ -2281,12 +2282,12 @@
 	if (ctxt) {
 		c = g_new (struct _sample_closure, 1);
 		c->sample = dest;
-		
+
 		u = marlin_undoable_new (crossfade_undo,
 					 NULL,
 					 crossfade_destroy,
 					 c);
-		
+
 		marlin_undo_context_add (ctxt, u);
 	}
 
@@ -2306,7 +2307,7 @@
 						(MarlinFadeFunc) sample_fade_func,
 						src_fade,
 						(MarlinFadeFunc) sample_fade_func,
-						dest_fade, operation, 
+						dest_fade, operation,
 						ctxt, error);
 
 		if (ret == FALSE) {
@@ -2315,7 +2316,7 @@
 			return FALSE;
 		}
 	}
-				
+
 	WRITE_UNLOCK (dest_priv->lock);
 	READ_UNLOCK (src_priv->lock);
 
@@ -2324,7 +2325,7 @@
 					 crossfade_undo,
 					 NULL,
 					 c);
-		
+
 		marlin_undo_context_add (ctxt, u);
 	}
 
@@ -2375,7 +2376,7 @@
 
 	READ_LOCK (src->priv->lock);
 	WRITE_LOCK (dest->priv->lock);
-	
+
 	/* create undoable */
 
 	fpms = (float) dest->priv->sample_rate / 1000.0f;
@@ -2421,16 +2422,16 @@
 	MarlinSamplePrivate *priv = sample->priv;
 	guint64 pos, new_pos;
 	int i;
-	
+
 	g_return_val_if_fail (IS_MARLIN_SAMPLE (sample), position);
-	
+
 	switch (coverage) {
 	case MARLIN_COVERAGE_BOTH:
 		pos = position;
 		for (i = 0; i < priv->channels; i++) {
 			new_pos = marlin_channel_next_zero (priv->channel_data->pdata[i],
 							    position);
-			
+
 			if (pos == position) {
 				pos = new_pos;
 			} else {
@@ -2454,7 +2455,7 @@
 		pos = position;
 		break;
 	}
-	
+
 	return pos;
 }
 
@@ -2463,7 +2464,7 @@
  * @sample: A #MarlinSample to search
  * @position: Start position of the search
  * @coverage: Coverage of the search
- * 
+ *
  * Find the previous zer0 crossing before @position
  *
  * Return value: The previous position or @position if it is the first.
@@ -2664,18 +2665,18 @@
 	int i;
 
 	g_return_val_if_fail (sample != NULL, FALSE);
-	
+
 	priv = sample->priv;
 
 	if (ctxt) {
 		c = g_new (struct _sample_closure, 1);
 		c->sample = sample;
-		
+
 		u = marlin_undoable_new (expand_range_undo,
 					 NULL,
 					 expand_range_destroy,
 					 c);
-		
+
 		marlin_undo_context_add (ctxt, u);
 	}
 
@@ -2686,12 +2687,12 @@
 	soundtouch = marlin_soundtouch_new ();
 	marlin_soundtouch_set_channels (soundtouch, 1);
 	marlin_soundtouch_set_sample_rate (soundtouch, priv->sample_rate);
-	marlin_soundtouch_set_tempo (soundtouch, 
+	marlin_soundtouch_set_tempo (soundtouch,
 				     ((float)old_length) / (float)new_length);
 	for (i = 0; i < priv->channels; i++) {
-		ret = marlin_channel_expand_range (priv->channel_data->pdata[i], 
-						   soundtouch, range->start, 
-						   range->finish, new_length, 
+		ret = marlin_channel_expand_range (priv->channel_data->pdata[i],
+						   soundtouch, range->start,
+						   range->finish, new_length,
 						   operation, ctxt, error);
 		if (ret) {
 			/* FIXME: We should pop off the last undoable
@@ -2710,7 +2711,7 @@
 					 expand_range_undo,
 					 NULL,
 					 c);
-		
+
 		marlin_undo_context_add (ctxt, u);
 	}
 
@@ -2771,7 +2772,7 @@
 
 	g_return_val_if_fail (src != NULL, FALSE);
 	g_return_val_if_fail (dest != NULL, FALSE);
-	
+
 	src_priv = src->priv;
 	dest_priv = dest->priv;
 
@@ -2798,12 +2799,12 @@
 	if (ctxt) {
 		c = g_new (struct _sample_closure, 1);
 		c->sample = dest;
-		
+
 		u = marlin_undoable_new (expand_mix_undo,
 					 NULL,
 					 expand_mix_destroy,
 					 c);
-		
+
 		marlin_undo_context_add (ctxt, u);
 	}
 
@@ -2815,11 +2816,11 @@
 	marlin_soundtouch_set_sample_rate (soundtouch, dest_priv->sample_rate);
 
 	for (i = 0; i < dest_priv->channels; i++) {
-		ret = marlin_channel_expand_mix (src_priv->channel_data->pdata[i], 
+		ret = marlin_channel_expand_mix (src_priv->channel_data->pdata[i],
 						 dest_priv->channel_data->pdata[i],
-						 soundtouch, 
-						 src_range->start, 
-						 src_range->finish, 
+						 soundtouch,
+						 src_range->start,
+						 src_range->finish,
 						 dest_range->start,
 						 dest_range->finish,
 						 src_db, dest_db,
@@ -2843,7 +2844,7 @@
 					 expand_mix_undo,
 					 NULL,
 					 c);
-		
+
 		marlin_undo_context_add (ctxt, u);
 	}
 
@@ -2858,7 +2859,124 @@
 
 	marlin_sample_data_changed (dest, dest_range);
 
-	return TRUE;	
+	return TRUE;
+}
+
+static void
+normalize_undo (gpointer data)
+{
+	struct _sample_closure *c = data;
+
+	g_object_set (G_OBJECT (c->sample),
+		      "dirty", TRUE,
+		      NULL);
+	marlin_sample_data_changed (c->sample, &(c->range));
+}
+
+static void
+normalize_destroy (gpointer data)
+{
+	g_free (data);
+}
+
+/**
+ * marlin_sample_normalize_range:
+ * @sample: A #MarlinSample
+ * @db: The volume to be set
+ * @range: A #MarlinRange
+ * @ctxt: A #MarlinUndoContext
+ * @error: A #GError
+ *
+ * Adjusts the volume of @sample to @db, within @range.
+ *
+ * Return value: TRUE on success, FALSE on failure with details in @error.
+ */
+gboolean
+marlin_sample_normalize_range (MarlinSample *sample,
+			       float db,
+			       MarlinRange *range,
+			       MarlinUndoContext *ctxt,
+			       GError **error)
+{
+	int i;
+	gboolean ret;
+	struct _sample_closure *c;
+	MarlinUndoable *u;
+
+	g_return_val_if_fail (IS_MARLIN_SAMPLE (sample), FALSE);
+
+	c = g_new (struct _sample_closure, 1);
+	c->sample = sample;
+	c->range.start = range->start;
+	c->range.finish = range->finish;
+	c->range.coverage = range->coverage;
+
+	u = marlin_undoable_new (normalize_undo,
+				 normalize_undo,
+				 normalize_destroy,
+				 c);
+
+	marlin_undo_context_add (ctxt, u);
+
+	WRITE_LOCK (sample->priv->lock);
+
+	switch (range->coverage) {
+	case MARLIN_COVERAGE_BOTH:
+		for (i = 0; i < sample->priv->channels; i++) {
+			ret = marlin_channel_normalize
+				(sample->priv->channel_data->pdata[i],
+				 range, db, NULL, ctxt, error);
+
+			if (ret == FALSE) {
+				WRITE_UNLOCK (sample->priv->lock);
+				return FALSE;
+			}
+		}
+		break;
+
+	case MARLIN_COVERAGE_LEFT:
+		ret = marlin_channel_normalize
+			(sample->priv->channel_data->pdata[0],
+			 range, db, NULL, ctxt, error);
+
+		if (ret == FALSE) {
+			WRITE_UNLOCK (sample->priv->lock);
+			return FALSE;
+		}
+
+		break;
+
+	case MARLIN_COVERAGE_RIGHT:
+		if (sample->priv->channels != 2) {
+			g_warning ("Attempting to adjust volume on RIGHT in a mono sample.");
+			WRITE_UNLOCK (sample->priv->lock);
+			return FALSE;
+		}
+
+		ret = marlin_channel_normalize
+			(sample->priv->channel_data->pdata[1],
+			 range, db, NULL, ctxt, error);
+
+		if (ret == FALSE) {
+			WRITE_UNLOCK (sample->priv->lock);
+			return FALSE;
+		}
+
+		break;
+
+	default:
+		break;
+	}
+
+	WRITE_UNLOCK (sample->priv->lock);
+
+	g_object_set (G_OBJECT (sample),
+		      "dirty", TRUE,
+		      NULL);
+
+	marlin_sample_data_changed (sample, range);
+
+	return TRUE;
 }
 
 /**

Modified: trunk/marlin/marlin-sample.h
==============================================================================
--- trunk/marlin/marlin-sample.h	(original)
+++ trunk/marlin/marlin-sample.h	Mon Feb 16 00:55:24 2009
@@ -75,9 +75,8 @@
 						 and destination samples did
 						 not match */
 	MARLIN_SAMPLE_ERROR_RATE_MISMATCH, /* Sample rate of the src and
-					      destination samples did not 
+					      destination samples did not
 					      match */
-						 
 } MarlinSampleError;
 
 GType marlin_sample_get_type (void);
@@ -205,7 +204,11 @@
 				   MarlinOperation   *operation,
 				   MarlinUndoContext *ctxt,
 				   GError           **error);
-
+gboolean marlin_sample_normalize_range (MarlinSample *sample,
+					float db,
+					MarlinRange *range,
+					MarlinUndoContext *ctxt,
+					GError **error);
 void marlin_sample_read_lock (MarlinSample *sample);
 void marlin_sample_read_unlock (MarlinSample *sample);
 

Modified: trunk/po/Makefile.in.in
==============================================================================
--- trunk/po/Makefile.in.in	(original)
+++ trunk/po/Makefile.in.in	Mon Feb 16 00:55:24 2009
@@ -56,7 +56,7 @@
 
 PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; else echo "$(ALL_LINGUAS)"; fi)
 
-USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for lang in $$LLINGUAS; do if test -n "`grep ^$$lang$$ $(srcdir)/LINGUAS 2>/dev/null`" -o -n "`echo $$ALINGUAS|tr ' ' '\n'|grep ^$$lang$$`"; then printf "$$lang "; fi; done; fi)
+USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for lang in $$LLINGUAS; do if test -n "`grep '^$$lang$$' $(srcdir)/LINGUAS 2>/dev/null`" -o -n "`echo $$ALINGUAS|tr ' ' '\n'|grep '^$$lang$$'`"; then printf "$$lang "; fi; done; fi)
 
 USE_LINGUAS=$(shell if test -n "$(USER_LINGUAS)" -o -n "$(LINGUAS)"; then LLINGUAS="$(USER_LINGUAS)"; else if test -n "$(PO_LINGUAS)"; then LLINGUAS="$(PO_LINGUAS)"; else LLINGUAS="$(ALL_LINGUAS)"; fi; fi; for lang in $$LLINGUAS; do printf "$$lang "; done)
 

Modified: trunk/src/marlin-window-menu.c
==============================================================================
--- trunk/src/marlin-window-menu.c	(original)
+++ trunk/src/marlin-window-menu.c	Mon Feb 16 00:55:24 2009
@@ -2,7 +2,7 @@
 /*
  *  Authors: Iain Holmes <iain gnome org>
  *
- *  Copyright 2002-2008 Iain Holmes
+ *  Copyright 2002-2009 Iain Holmes
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of version 2 of the GNU General Public
@@ -422,14 +422,14 @@
 	MarlinSample *sample;
 	MarlinUndoManager *undo;
 	MarlinUndoContext *ctxt;
-	
+
 	g_object_get (G_OBJECT (data),
 		      "sample", &sample,
 		      NULL);
 
 	undo = marlin_base_window_get_undo_manager (base);
 	ctxt = marlin_undo_manager_context_begin (undo, _("Select Nothing"));
-	
+
 	marlin_window_select_none (MARLIN_WINDOW (data), ctxt);
 
 	marlin_undo_manager_context_end (undo, ctxt);
@@ -458,7 +458,7 @@
 	MarlinSample *sample;
 	MarlinUndoManager *undo;
 	MarlinUndoContext *ctxt;
-	
+
 	g_object_get (G_OBJECT (data),
 		      "sample", &sample,
 		      NULL);
@@ -479,7 +479,7 @@
 	MarlinSample *sample;
 	MarlinUndoManager *undo;
 	MarlinUndoContext *ctxt;
-	
+
 	g_object_get (G_OBJECT (data),
 		      "sample", &sample,
 		      NULL);
@@ -500,7 +500,7 @@
 	MarlinSample *sample;
 	MarlinUndoManager *undo;
 	MarlinUndoContext *ctxt;
-	
+
 	g_object_get (G_OBJECT (data),
 		      "sample", &sample,
 		      NULL);
@@ -522,7 +522,7 @@
 	MarlinSample *sample;
 	MarlinUndoManager *undo;
 	MarlinUndoContext *ctxt;
-	
+
 	g_object_get (G_OBJECT (data),
 		      "sample", &sample,
 		      NULL);
@@ -704,34 +704,41 @@
 
 static void
 process_adjust_volume (GtkAction *action,
-		       gpointer data)
+		       gpointer   data)
 {
 	marlin_window_adjust_volume (MARLIN_WINDOW (data));
 }
 
 static void
+process_normalize (GtkAction    *action,
+		   MarlinWindow *window)
+{
+	marlin_window_normalize (window);
+}
+
+static void
 process_insert_silence (GtkAction *action,
-			gpointer data)
+			gpointer   data)
 {
 	marlin_window_insert_silence (MARLIN_WINDOW (data));
 }
 
 static void
 process_change_channels (GtkAction *action,
-			 gpointer data)
+			 gpointer   data)
 {
 	marlin_window_change_channels (MARLIN_WINDOW (data));
 }
 
 static void
 process_split_sample (GtkAction *action,
-		      gpointer data)
+		      gpointer   data)
 {
 	marlin_window_split_sample (MARLIN_WINDOW (data));
 }
 
 static void
-process_reverse_sample (GtkAction *action,
+process_reverse_sample (GtkAction    *action,
 			MarlinWindow *window)
 {
 	marlin_window_reverse_sample (window);
@@ -836,7 +843,7 @@
 /* FIXME: All these displays should use the same gconf key,
    and one place sets it and they all pay attention to it. */
 static void
-scale_action_changed (GtkAction *action, 
+scale_action_changed (GtkAction *action,
 		      GtkRadioAction *current,
 		      MarlinWindow *window)
 {
@@ -1069,6 +1076,9 @@
 	{ "ProcessVolume", NULL, N_("Adjust Sample Volume..."), NULL,
 	  N_("Adjust the volume of the sample"),
 	  G_CALLBACK (process_adjust_volume) },
+	{ "ProcessNormalize", NULL, N_("Normalize Sample Volume..."), NULL,
+	  N_("Normalize the volume of the sample"),
+	  G_CALLBACK (process_normalize) },
 	{ "ProcessInsertSilence", NULL, N_("Insert Silence..."), NULL,
 	  N_("Insert silence into the sample"),
 	  G_CALLBACK (process_insert_silence) },

Modified: trunk/src/marlin-window.c
==============================================================================
--- trunk/src/marlin-window.c	(original)
+++ trunk/src/marlin-window.c	Mon Feb 16 00:55:24 2009
@@ -2466,12 +2466,14 @@
 		set_path_name (ag, "ProcessInvert", _("Invert Sample"));
 		set_path_name (ag, "ProcessVolume", _("Adjust Sample Volume..."));
 		set_path_name (ag, "ProcessReverse", _("Reverse Sample"));
+		set_path_name (ag, "ProcessNormalize", _("Normalize Sample"));
 	} else {
 		/* Selection */
 		set_path_name (ag, "ProcessMute", _("Mute Selection"));
 		set_path_name (ag, "ProcessInvert", _("Invert Selection"));
 		set_path_name (ag, "ProcessVolume", _("Adjust Selection Volume..."));
 		set_path_name (ag, "ProcessReverse", _("Reverse Selection"));
+		set_path_name (ag, "ProcessNormalize", _("Normalize Selection"));
 	}
 
 	if (priv->sample) {
@@ -5496,14 +5498,14 @@
 
 	priv->edit_marker_dialog = marlin_edit_marker_dialog_new (MARLIN_BASE_WINDOW (window));
 	g_signal_connect (priv->edit_marker_dialog, "destroy",
-			  G_CALLBACK (gtk_widget_destroyed), 
+			  G_CALLBACK (gtk_widget_destroyed),
 			  &priv->edit_marker_dialog);
 	gtk_widget_show (priv->edit_marker_dialog);
 }
 
 /**
  * marlin_window_is_empty:
- * window: A #MarlinWindow object
+ * @window: A #MarlinWindow object
  *
  * Checks if @window has a sample loaded or not.
  *
@@ -5524,3 +5526,43 @@
 
 	return (frames == 0);
 }
+
+void
+marlin_window_normalize (MarlinWindow *window)
+{
+	MarlinWindowPrivate *priv = window->priv;
+	MarlinUndoContext *ctxt;
+	MarlinRange range;
+	gboolean ret;
+	GError *error = NULL;
+
+	marlin_sample_selection_get (priv->selection, &(range.coverage),
+				     &(range.start), &(range.finish));
+	if (range.coverage == MARLIN_COVERAGE_NONE) {
+		guint64 frames;
+
+		/* Adjust whole sample */
+		g_object_get (G_OBJECT (priv->sample),
+			      "total_frames", &frames,
+			      NULL);
+		ctxt = marlin_undo_manager_context_begin (priv->undo,
+							  _("Normalize Sample"));
+
+		range.coverage = MARLIN_COVERAGE_BOTH;
+		range.start = 0;
+		range.finish = frames - 1;
+	} else {
+		ctxt = marlin_undo_manager_context_begin (priv->undo,
+							  _("Normalize Selection"));
+
+	}
+
+	ret = marlin_sample_normalize_range (priv->sample, 0.0,
+					     &range, ctxt, &error);
+
+	if (ret == FALSE) {
+		g_warning ("marlin_sample_adjust_volume_range failed");
+	}
+
+	marlin_undo_manager_context_end (priv->undo, ctxt);
+}

Modified: trunk/src/marlin.xml
==============================================================================
--- trunk/src/marlin.xml	(original)
+++ trunk/src/marlin.xml	Mon Feb 16 00:55:24 2009
@@ -91,6 +91,7 @@
 <menu name="ProcessMenu" action="Process">
 	<menuitem name="ProcessMute" action="ProcessMute"/>
 	<menuitem name="ProcessVolume" action="ProcessVolume"/>
+	<menuitem name="ProcessNormalize" action="ProcessNormalize"/>
 	<menuitem name="ProcessInsertSilence" action="ProcessInsertSilence"/>
 	<menuitem name="ProcessSwapMenu" action="ProcessSwapChannels"/>
 	<menuitem name="ProcessAdjustChannelsMenu" action="ProcessAdjustChannels"/>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]