PageRenderTime 46ms CodeModel.GetById 12ms app.highlight 28ms RepoModel.GetById 1ms app.codeStats 0ms

/io/wavelet.d

http://github.com/wilkie/djehuty
D | 182 lines | 103 code | 52 blank | 27 comment | 10 complexity | f3f94dd2c666b1c97eadd54e404e7ae7 MD5 | raw file
  1module io.wavelet;
  2
  3import core.stream;
  4import core.string;
  5import core.definitions;
  6import core.time;
  7
  8import io.audio;
  9import io.console;
 10
 11import math.common;
 12import math.vector;
 13
 14enum Interpolate {
 15	Zeroth,
 16	Linear,
 17}
 18
 19// Section: Core/Streams
 20
 21// Description: This class represents an audio buffer.  You can do simple transforms on the audio data using the provided methods.  It is essentially a Stream, and you can read and write to the buffer in the same fashion.
 22class Wavelet : Stream {
 23	// Constructors //
 24
 25	// Description: Will create a small buffer.  This will presumedly be resized.
 26	this() {
 27		super(1);
 28	}
 29
 30	// -- Methods -- //
 31
 32	// Description: Will get the format of the audio information.
 33	// Returns: An AudioFormat struct containing useful information such as sample rate and average bytes per second.
 34	AudioFormat audioFormat() {
 35		return _fmt;
 36	}
 37
 38	// Description: Will set the audio format of the buffer.  Audio Codecs will set this automatically, but if the buffer format is otherwise unknown, it can be set using this function.
 39	// audFormat: An AudioFormat struct describing the contents of the buffer.
 40	void setAudioFormat(AudioFormat audFormat) {
 41		_fmt = audFormat;
 42	}
 43
 44
 45
 46	// -- Computations -- //
 47
 48	void upSample(Interpolate interpType) {
 49	}
 50
 51	void downSample(Interpolate interpType) {
 52	}
 53
 54	void pitchBend() {
 55	}
 56
 57	void pitchShift() {
 58	}
 59
 60	// Description: This function will shorten the wavelet to a specified region.
 61	void crop(Time start) {
 62		// is this necessary?
 63		if (start > time() || start is null) {
 64			// error
 65			Console.put("error");
 66			return;
 67		}
 68
 69		Time len = time() - start;
 70
 71		int newLength;
 72		int newStartPos;
 73
 74		ubyte olddata[] = _data;
 75
 76
 77		newLength = cast(int)((_fmt.averageBytesPerSecond / 1000) * (len.microseconds / 1000));
 78		newStartPos = cast(int)((_fmt.averageBytesPerSecond / 1000) * (start.microseconds / 1000));
 79
 80		_data = new ubyte[newLength];
 81		_data[0..$] = olddata[newStartPos..(newStartPos + newLength)];
 82
 83		_length = newLength;
 84		_capacity = newLength;
 85
 86	}
 87
 88	// Description: This function will shorten the wavelet to a specified region.
 89	void crop(Time start, Time len) {
 90		// is this necessary?
 91		if (start > time()) {
 92			// error
 93			Console.put("error");
 94			return;
 95		}
 96
 97		if (len + start > time()) {
 98			// error
 99			Console.put("error");
100			return;
101		}
102
103		int newLength;
104		int newStartPos;
105
106		ubyte olddata[] = _data;
107
108
109		newLength = cast(int)((_fmt.averageBytesPerSecond / 1000) * (len.microseconds / 1000));
110		newStartPos = cast(int)((_fmt.averageBytesPerSecond / 1000) * (start.microseconds / 1000));
111
112		_data = new ubyte[newLength];
113		_data[0..$] = olddata[newStartPos..(newStartPos + newLength)];
114
115		_length = newLength;
116		_capacity = newLength;
117
118	}
119
120	// Description: This function will return the amount of time this block represents
121	Time time() {
122		Time tme = new Time();
123
124		// the amount of bytes / amount of bytes per second = seconds
125		if (_fmt.averageBytesPerSecond == 0) {
126			return tme;
127		}
128
129		float amtSeconds = (cast(float)length() / cast(float)_fmt.averageBytesPerSecond);
130
131		tme.microseconds = cast(long)(amtSeconds * 1000000);
132
133		return tme;
134	}
135
136	cdouble[] fourier(int samples = 512, uint skipSamples = 0) {
137		if ((samples + skipSamples) * _fmt.numChannels > (this.length / 2)) {
138			samples = cast(int)((this.length / 2 / _fmt.numChannels) - skipSamples);
139		}
140		if (samples < 0) {
141			return [];
142		}
143
144		uint rem = 1;
145
146		// floor samples to nearest power of 2
147		while(samples > 0) {
148			samples >>= 1;
149			rem <<= 1;
150		}
151		rem >>= 1;
152
153		cdouble[] ret = new cdouble[rem];
154
155		// I'll just average the channels, if possible
156		short* ptr = cast(short*)&_data[0];
157
158		size_t idx = skipSamples * _fmt.numChannels;
159		for(size_t sample = 0; sample < rem; sample++, idx += _fmt.numChannels) {
160			cdouble data = 0.0 + 0.0i;
161			for(size_t channel = 0; channel < _fmt.numChannels; channel++) {
162				data += (cast(cdouble)ptr[idx + channel] / cast(cdouble)short.max);
163			}
164			ret[sample] = data / _fmt.numChannels;
165		}
166
167		return ret.fft();
168	}
169
170private:
171
172	// Reference to the Audio Format
173	// of this collection of samples
174
175	// This is used for playback and is
176	// also used for calculations and
177	// transformations
178
179	AudioFormat _fmt;
180}
181
182//alias WaveletImpl!(StreamAccess.AllAccess) Wavelet;