# --- ROCK-COPYRIGHT-NOTE-BEGIN ---
# 
# This copyright note is auto-generated by ./scripts/Create-CopyPatch.
# Please add additional copyright information _after_ the line containing
# the ROCK-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by
# the ./scripts/Create-CopyPatch script. Do not edit this copyright text!
# 
# ROCK Linux: rock-src/package/clifford/mixmagic/pitch.patch
# ROCK Linux is Copyright (C) 1998 - 2005 Clifford Wolf
# 
# This patch file is dual-licensed. It is available under the license the
# patched project is licensed under, as long as it is an OpenSource license
# as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms
# of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
# 
# --- ROCK-COPYRIGHT-NOTE-END ---


This patch adds pitch shifting to mixmagic. (by Clifford)

--- ./src/block.c.orig	Sat Mar  9 11:06:32 2002
+++ ./src/block.c	Mon May 13 20:16:56 2002
@@ -834,6 +834,7 @@
 
 	b->start = block->start + MIN (block->selection_start, block->selection_end);
 	b->length = ABS (block->selection_start - block->selection_end);
+	block->length_unpitched = block->length * block->pitch;
 	b->sample = sample_ref (block->sample);
 	b->position = block->position + MIN (block->selection_start, block->selection_end); 
 
@@ -1143,6 +1144,8 @@
 				newBlock->sample = sample_ref (block->sample);
 				newBlock->start = block->start;
 				newBlock->length = block->length;
+				newBlock->length_unpitched = block->length_unpitched;
+				newBlock->pitch = block->pitch;
 				
 				/* Position it on the same place as the popup menu */
 				newBlock->position = block->position;
@@ -1183,8 +1186,8 @@
 block_draw (Block *block)
 {
 	gint i, width, height;
-	gint offset, value;
-	GString * start_gs , * len_gs ;
+	gint offset, offset_start, value;
+	GString * start_gs , * len_gs , * pitch_gs;
 
 	g_assert (IS_BLOCK(block));
 
@@ -1210,11 +1213,13 @@
 			    width,
 			    height);
 
-	offset = block->start / INDEX_RATIO;
+	offset_start = block->start / INDEX_RATIO;
+	offset = 0;
 
 	for (i = 0; i < width;i++) {
 		value = index_get_average (block->sample->index, 
-					   offset, block->start / INDEX_RATIO,
+					   offset_start + offset * block->pitch,
+		                           block->start / INDEX_RATIO,
 					   block->track->song->x_scale / INDEX_RATIO, 
 					   block->sample->length / INDEX_RATIO / 2) / ((float)0x7f / height);
 		gdk_draw_line (block->pixmap,
@@ -1254,13 +1259,42 @@
 
 	/* Draw title */
 
+	gdk_draw_text  (block->pixmap,
+		       GTK_WIDGET(block)->style->font,
+		       GTK_WIDGET(block)->style->fg_gc[GTK_WIDGET(block)->state],
+		       10, 15,
+		       "F:",
+		       2);
+
 	gdk_draw_text (block->pixmap,
 		       GTK_WIDGET(block)->style->font,
 		       GTK_WIDGET(block)->style->fg_gc[GTK_WIDGET(block)->state],
-		       0, 10,
+		       25, 15,
 		       block->sample->id,
 		       strlen (block->sample->id));
 
+	/* Draw Pitch Value */
+
+	pitch_gs = g_string_sized_new(20);
+
+	pitch_gs->len = g_snprintf(pitch_gs->str, 20, "%c%02d.%02d %%",
+		block->pitch == 0 ? '0' : (block->pitch > 0 ? '+' : '-'),
+		abs(block->pitch*10000 - 10000) / 100,
+		abs(block->pitch*10000 - 10000) % 100);
+
+	gdk_draw_text  (block->pixmap,
+		       GTK_WIDGET(block)->style->font,
+		       GTK_WIDGET(block)->style->fg_gc[GTK_WIDGET(block)->state],
+		       10, 30,
+		       "P:",
+		       2);
+
+	gdk_draw_text (block->pixmap,
+		       GTK_WIDGET(block)->style->font,
+		       GTK_WIDGET(block)->style->fg_gc[GTK_WIDGET(block)->state],
+		       25, 30,
+		       pitch_gs->str,
+		       pitch_gs->len);
 
 	/* Draw start time */
 
@@ -1281,14 +1315,14 @@
 	gdk_draw_text  (block->pixmap,
 		       GTK_WIDGET(block)->style->font,
 		       GTK_WIDGET(block)->style->fg_gc[GTK_WIDGET(block)->state],
-		       0, height - 20,
+		       10, height - 20,
 		       "S:",
 		       2);
 
 	gdk_draw_text  (block->pixmap,
 		       GTK_WIDGET(block)->style->font,
 		       GTK_WIDGET(block)->style->fg_gc[GTK_WIDGET(block)->state],
-		       15, height - 20,
+		       25, height - 20,
 		       start_gs->str,
 		       start_gs->len);
 
@@ -1313,14 +1347,14 @@
 	gdk_draw_text (block->pixmap,
 		       GTK_WIDGET(block)->style->font,
 		       GTK_WIDGET(block)->style->fg_gc[GTK_WIDGET(block)->state],
-		       0, height - 5,
+		       10, height - 5,
 		       "L:",
 		       2);
 
 	gdk_draw_text (block->pixmap,
 		       GTK_WIDGET(block)->style->font,
 		       GTK_WIDGET(block)->style->fg_gc[GTK_WIDGET(block)->state],
-		       15, height - 5,
+		       25, height - 5,
 		       len_gs->str,
 		       len_gs->len);
 
@@ -1481,6 +1515,73 @@
 	gtk_widget_draw (GTK_WIDGET (block), NULL);
 }
 
+static void block_set_pitch (GtkWidget *widget, Block *block, gfloat newpitch) {
+	block->pitch = newpitch;
+	block->length = block->length_unpitched / newpitch;
+	block_update (block);
+	song_set_dirty (block->track->song, TRUE);
+}
+
+static void block_dec_pitch_1 (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, block->pitch - 0.0001); }
+
+static void block_dec_pitch_3 (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, block->pitch - 0.0003); }
+
+static void block_dec_pitch_5 (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, block->pitch - 0.0005); }
+
+static void block_dec_pitch_10 (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, block->pitch - 0.0010); }
+
+static void block_dec_pitch_30 (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, block->pitch - 0.0030); }
+
+static void block_dec_pitch_50 (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, block->pitch - 0.0050); }
+
+static void block_dec_pitch_100 (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, block->pitch - 0.0100); }
+
+static void block_dec_pitch_300 (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, block->pitch - 0.0300); }
+
+static void block_dec_pitch_500 (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, block->pitch - 0.0500); }
+
+
+static void block_pitch_reset (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, 1); }
+
+
+static void block_inc_pitch_1 (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, block->pitch + 0.0001); }
+
+static void block_inc_pitch_3 (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, block->pitch + 0.0003); }
+
+static void block_inc_pitch_5 (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, block->pitch + 0.0005); }
+
+static void block_inc_pitch_10 (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, block->pitch + 0.0010); }
+
+static void block_inc_pitch_30 (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, block->pitch + 0.0030); }
+
+static void block_inc_pitch_50 (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, block->pitch + 0.0050); }
+
+static void block_inc_pitch_100 (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, block->pitch + 0.0100); }
+
+static void block_inc_pitch_300 (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, block->pitch + 0.0300); }
+
+static void block_inc_pitch_500 (GtkWidget *widget, Block *block)
+	{ block_set_pitch (widget, block, block->pitch + 0.0500); }
+
+
 static void
 block_select_all (GtkWidget *widget, Block *block)
 {
@@ -1534,6 +1635,26 @@
 	GNOMEUIINFO_SEPARATOR,
 	GNOMEUIINFO_ITEM_NONE (N_("Convert to loopblock"), N_("Convert to loopblock"), block_convert_to_loopblock),
 	GNOMEUIINFO_SEPARATOR,
+	GNOMEUIINFO_ITEM_NONE (N_("Pitch -5.00"), N_(""), block_dec_pitch_500),
+	GNOMEUIINFO_ITEM_NONE (N_("Pitch -3.00"), N_(""), block_dec_pitch_300),
+	GNOMEUIINFO_ITEM_NONE (N_("Pitch -1.00"), N_(""), block_dec_pitch_100),
+	GNOMEUIINFO_ITEM_NONE (N_("Pitch -0.50"), N_(""), block_dec_pitch_50),
+	GNOMEUIINFO_ITEM_NONE (N_("Pitch -0.30"), N_(""), block_dec_pitch_30),
+	GNOMEUIINFO_ITEM_NONE (N_("Pitch -0.10"), N_(""), block_dec_pitch_10),
+	GNOMEUIINFO_ITEM_NONE (N_("Pitch -0.05"), N_(""), block_dec_pitch_5),
+	GNOMEUIINFO_ITEM_NONE (N_("Pitch -0.03"), N_(""), block_dec_pitch_3),
+	GNOMEUIINFO_ITEM_NONE (N_("Pitch -0.01"), N_(""), block_dec_pitch_1),
+	GNOMEUIINFO_ITEM_NONE (N_("Reset Pitch"), N_(""), block_pitch_reset),
+	GNOMEUIINFO_ITEM_NONE (N_("Pitch +0.01"), N_(""), block_inc_pitch_1),
+	GNOMEUIINFO_ITEM_NONE (N_("Pitch +0.03"), N_(""), block_inc_pitch_3),
+	GNOMEUIINFO_ITEM_NONE (N_("Pitch +0.05"), N_(""), block_inc_pitch_5),
+	GNOMEUIINFO_ITEM_NONE (N_("Pitch +0.10"), N_(""), block_inc_pitch_10),
+	GNOMEUIINFO_ITEM_NONE (N_("Pitch +0.30"), N_(""), block_inc_pitch_30),
+	GNOMEUIINFO_ITEM_NONE (N_("Pitch +0.50"), N_(""), block_inc_pitch_50),
+	GNOMEUIINFO_ITEM_NONE (N_("Pitch +1.00"), N_(""), block_inc_pitch_100),
+	GNOMEUIINFO_ITEM_NONE (N_("Pitch +3.00"), N_(""), block_inc_pitch_300),
+	GNOMEUIINFO_ITEM_NONE (N_("Pitch +5.00"), N_(""), block_inc_pitch_500),
+	GNOMEUIINFO_SEPARATOR,
 	GNOMEUIINFO_ITEM_NONE (N_("Select all"), N_("Make the selection cover the whole block"), block_select_all),
 	GNOMEUIINFO_END
 };
@@ -1640,24 +1761,30 @@
 mix_into_buffer (Block *block, gint16 *buffer, gint position, gint length)
 {
 	gint16 *data;
-	gint i;
+	gint i, data_offset, data_xoffset;
 	
-	data = (gint16 *)(block->sample->data + 
-			  (block->start + position - block->position) * block->sample->byte_p_spl);
-		
-	for (i = 0;i < length / (sizeof (guint16) * 2);i++) {
+	data = (gint16 *)(block->sample->data +
+				(block->start - block->position) *
+				block->sample->byte_p_spl);
+	data_offset = position;
+
+	for (i = 0; i < length / (sizeof (guint16) * 2); i++) {
+
+		data_xoffset = data_offset * block->pitch;
+		data_xoffset *= block->sample->num_channels;
 
 		mixer_mix_sample_into_buffer (buffer,
-					      data,
+					      data + data_xoffset,
 					      block->amp_env, 
 					      block->pan_env, 
 					      block->track->amp,
 					      block->track->pan,
-					      position - block->position + i, block->sample->num_channels);
+					      position - block->position + i,
+					      block->sample->num_channels);
 		
-		data += block->sample->num_channels;
+		data_offset++;
 		buffer += 2;
 	}
 }
 
 /*
@@ -1675,8 +1813,11 @@
 	
 	block->start = atoi ((ptr = xmlGetProp (node, "start")));
 	g_free (ptr);
-	block->length = atoi ((ptr = xmlGetProp (node, "length")));
+	block->length_unpitched = atoi ((ptr = xmlGetProp (node, "length")));
 	g_free (ptr);
+	block->pitch = (float)atoi ((ptr = xmlGetProp (node, "pitch"))) / 10000;
+	g_free (ptr);
+	block->length = (float)block->length_unpitched * block->pitch;
 	block->position = atoi ((ptr = xmlGetProp (node, "position")));
 	g_free (ptr);
 	ptr = xmlGetProp (node, "sample");
--- ./src/track.c.orig	Tue Mar 12 06:39:42 2002
+++ ./src/track.c	Mon Mar 11 20:53:32 2002
@@ -328,6 +328,8 @@
 
 		block->start = 0;
 		block->length = sample_get_length(block->sample);
+		block->length_unpitched = sample_get_length(block->sample);
+		block->pitch=1;
 
 		/* Position it on the same place as the popup menu */
 		block->position = (x + (gint)(GTK_LAYOUT (track->layout)->hadjustment->value)) * track->song->x_scale;
--- ./src/block.h.orig	Mon Mar 11 20:47:57 2002
+++ ./src/block.h	Mon Mar 11 20:37:16 2002
@@ -89,6 +89,9 @@
 	gint length;			/* The length of this block */
 	gint position;			/* Position in time */
 
+	gfloat pitch;			/* Pitch shifting (in %) */
+	gint length_unpitched;		/* The length before pitch is applied */
+
 	Sample *sample;			/* The sample assosiated with this block */
 
 	GList *amp_env;			/* Pointer to this blocks amplitude envelope or NULL */