Need some help with my double-time method

closed account (365X92yv)
I've got a bunch of stuff working in my mixer program. More specifically though, I have a wav file that I need to double time. What I mean by double time is this:

Double Time
This effect slows down the sound so that it takes twice as long to play. This means you’ll end up with an array that’s double the size, with every sample put in twice.

Here is my code for the method I have right now.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
wav.h
#ifndef INCLUDE_WAV
#define	INCLUDE_WAV

#include <iostream>
using namespace std;

class Wav
{
public:
	// constructors
	Wav();
	Wav( string filename );
	~Wav();
	Wav( const Wav& other );
	Wav& operator=( const Wav& other);

	//methods
	void Play(); // method to play the sound
	void Reverse();	// method to reverse the sound
	void Half(); // method to half-time the sound
	void Double(); // method to double-time the sound
	void Mix(); // method to mix the two sounds
	void Echo(); // metohd to echo the sound

	string toString(int &position);

private:
	// Variables	
	// sample storage
	double * samples;
	unsigned int sampleCount;

	// other important info from the WAV format
	double sampleRate;
    unsigned int bitsPerSample;
    unsigned int channels;
	string fileName;
};

#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
wav.cpp
#include <string>
#include <sstream>
#include "wav.h"
#include "wav_in.h"
#include "wav_out.h"
#include "windows.h"

Wav::Wav()
{
	sampleRate = 0;
    bitsPerSample = 0;
    channels = 0;
	sampleCount = 0;
	fileName = "";
	samples = NULL;
}

Wav::Wav( string filename )
{
	// use WAV_IN object to read WAVE file
	WAV_IN infile( filename.c_str() );
	fileName = filename;
	// get WAVE parameters from the infile object
	sampleRate = infile.get_sample_rate_hz();
    bitsPerSample = infile.get_bits_per_sample();
    channels = infile.get_num_channels();
	sampleCount = infile.get_num_samples();

	samples = new double[sampleCount];
	// read the sample values and store them in samples
	for( unsigned int i=0; i<sampleCount; i++ )
	{
		samples[i] = infile.read_current_input();
    }
}

Wav::~Wav()
{
	cout << "WAV DESTRUCTION!" << endl;
	cout << fileName << endl;
	if(samples != NULL)
		delete []samples;
}

Wav::Wav( const Wav& other )
{
	cout << "MIMIC, AWAYYYYYYY" << endl;
	double *samplesCopy = new double[other.sampleCount];
	sampleRate = other.sampleRate;
	bitsPerSample = other.bitsPerSample;
    channels = other.channels;
	sampleCount = other.sampleCount;
	fileName = other.fileName;
	for( unsigned int i=0; i<sampleCount; i++ )
	{
		samplesCopy[ i ] = other.samples[ i ];
    }
	samples = samplesCopy;
	delete []samplesCopy;
}

Wav& Wav::operator=( const Wav& other)
{
	if(this != &other)
	{
		double *tempWav = new double[other.sampleCount];
		sampleRate = other.sampleRate;
		bitsPerSample = other.bitsPerSample;
	    channels = other.channels;
		sampleCount = other.sampleCount;
		fileName = other.fileName;
		for( unsigned int i=0; i<sampleCount; i++ )
		{
			tempWav[ i ] = other.samples[ i ];
		}
	}
	return *this;
}

void Wav::Reverse()
{
	// iterate over half the samples
	for( unsigned int i=0; i<sampleCount/2; i++ )
	{
		// swapping with the other half
		double temp = samples[i];
		samples[i] = samples[sampleCount-i-1];
		samples[sampleCount-i-1] = temp;
	}
}

void Wav::Play()
{
	// setup a WAV_OUT object to write the file to disk
	WAV_OUT outfile( sampleRate, bitsPerSample, channels );

	// add the samples to the outfile object
	for( unsigned int i=0; i<sampleCount; i++ )
	{
		outfile.write_current_output( samples[i] );
    }

	// and write it out to a temporary file
	outfile.save_wave_file( "out.wav" );
 
	// call the windows API to play that temporary file
	PlaySound( TEXT("out.wav"), NULL, SND_FILENAME );
}

void Wav::Half() // HALVES THE WAV FILE
{
	// setup a WAV_OUT object to write the file to disk
	WAV_OUT outfile( sampleRate, bitsPerSample, channels );

	// add the samples to the outfile object
	for( unsigned int i=0; i<sampleCount; i++ )
	{
		if((i % 2) == 0)
		{
			outfile.write_current_output( samples[i] );
		}
    }

	// and write it out to a temporary file
	outfile.save_wave_file( "out.wav" );
 
	// call the windows API to play that temporary file
	PlaySound( TEXT("out.wav"), NULL, SND_FILENAME );
}
//////////////////////////////////////////////////////////////////
// NEEDS TO BE FIXED
void Wav::Double() // NOT COMPLETE, OR CORRECT
{
	double *temp = new double[sampleCount*2];
	double copySamp = 0;

	// iterate over half the samples 
	for( unsigned int i=0; i<sampleCount; i++ )
	{
		if(samples[ i ] != copySamp)
		{
			if(temp[ i ] != copySamp)
			{
				copySamp = samples[ i ];
				temp[ i ] = copySamp;
				temp[ i + 1 ] = copySamp;
				cout << temp[ i ] << " " << temp[ i + 1 ] << " " << i << endl;
			}
			else
			{
				copySamp = samples[ i ];
				// need to get samples[ i ] since its data is different
				// and store it someplace, then write it to where I want.
			}
		}
	}

	for(unsigned int i=0;i<sampleCount;i++)
	{
		cout << temp[ i ] << " " << i << endl;
	}

}
// DONT MIND THE NONSENSE I HAVE IN HERE RIGHT NOW
//////////////////////////////////////////////////////////////////////
void Wav::Mix() // HAVE ONLY COPIED THE REVERSE METHOD INTO HERE
{
	// iterate over half the samples
	for( unsigned int i=0; i<sampleCount/2; i++ )
	{
		// swapping with the other half
		double temp = samples[i];
		samples[i] = samples[sampleCount-i-1];
		samples[sampleCount-i-1] = temp;
	}
}

void Wav::Echo() // ONLY COPIED THE REVERSE METHOD INTO HERE
{
	// iterate over half the samples
	for( unsigned int i=0; i<sampleCount/2; i++ )
	{
		// swapping with the other half
		double temp = samples[i];
		samples[i] = samples[sampleCount-i-1];
		samples[sampleCount-i-1] = temp;
	}
}

string Wav::toString(int &position)
{
	ostringstream oss;

	oss << (position + 1) << ": " << fileName ;

	return oss.str();
}


For all intents and purposes, the only code you should be worried about is the
void Wav::Double(); method.
When you iterate over the samples array you know exactly where you should put the sample values in the temp array. These are positions 2 * i and 2 * i + 1, so you don't need any ifs in your code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void Wav::Double() 
{
	double *temp = new double[sampleCount*2];
	for( unsigned int i=0; i<sampleCount; i++ )
	{
		temp[2 * i] = temp[2 * i + 1] = samples[i];
	}

	for(unsigned int i=0;i<sampleCount * 2;i++)
	{
		cout << temp[ i ] << " " << i << endl;
	}

}


There's also a bug in the last stream output loop (not enough iterations there, fix is in bold).
Last edited on
closed account (365X92yv)
That did the trick. My only concern now is getting it to work like my Half() method. It seems that what I'm doing in the Double() method copies it to a new array and positions everything correctly but for the life of me, I can't seem to get it to play like the Half() method does. What I do know is the reason the Half() method works is I'm writing the values to the out.wav file so when its done writing, it plays. It'd be cool if I could figure out how to do the same for the Double() method. I think what's stopping me from doing that is the fact that the data members I'm passing in are certain sizes and I'd need to change them to manage it correctly.

Grr. Wall of friggin' text.

Half() method works by writing every other value to the samples pointer array. So with that idea, The Double() method needs to take the samples pointer array, double the size, then write the new values, copying every samples[ i ] value into the new array. Anyways, that's all. I'll keep working on my code.
Topic archived. No new replies allowed.