#
# CS 190C, Spring 2009
#
# YOUR NAME
#
# Project 1
# this file gives templates for the eight audio primitives (part 1) and
# the functions that can be used as the optimal one (hand in with part 2)
#
import math
from numpy import zeros, empty, array, append
# Helpful constants
WAVE_MAX = 32767 # Max sample value
WAVE_MIN = -32768 # Min sample value
SAMPLE_FREQUENCY = 22050 # Sampling frequency in Hz
from snd_io import read_wav_file, save_wav_file, play
########################################################################
#
# Required functions skeletons
#
# submit the eight required function is a file named primitives.py
#
########################################################################
def scale_volume(data, factor):
"""
scale_volume(data, factor)
This function takes samples specified in data and scales them all
by a constant factor. To accomplish this, every element of the data
array is multiplied by a constant factor which will correspondingly
increase or decrease the volume of the wave (corresponding to factors
greater than 1 or less than 1 respectively). Note that this may result
int samples that are out of range. The following actions are taken:
- If a scaled sample is greater than WAVE_MAX, set it to WAVE_MAX
- If a scaled sample is less than WAVE_MIN, set it to WAVE_MIN
This will result in clipping.
"""
return
########################################################################
def normalize(data):
"""
normalize(data)
This function maximizes the possible volume of a wave by ensuring that
the maximum possible sample scaling is used. In principle this is similar
to the scale_volume() function except that the scaled values are
maximized and should always be in range. Because of this it is safe to
use the array operations.
The following functions may be helpful:
max(a) - returns the laegest element of a
min(a) - returns the smallest element of a
abs(x) - returns the absolute value of x
Note the special case where all samples are 0.
"""
return
########################################################################
def echo(data, delay, level):
"""
echo(data, delay, level)
This function takes an array of samples, a delay in seconds,
and an echo level.
Remember that the delay is in seconds, and the value must be
translated to have a meaning in terms of actual sampling.
The SAMPLE_FREQUENCY value indicates the number of samples/sec.
The level should be between 0 and 1. The level indicates the intensity
of the echo in proportion to the original sound. Correspondingly, the
original wave will scaled by a factor of (1 - level).
To create an echo effect, the sound is shifted by a certain number of
samples. The pieces of the waves that do not overlap are matched by
silence in the other wave. For each sample, the result is the weighted
average:
result = (1-level)*orig_sample + level*echo_sample
NOTE: Since the resulting array is not the same size as the input array,
this function returns a new array containing the result. Also, remember
that delay may be a floating point number, so it is important to make
sure that when calculating the number of samples in the delay that the
result is an integer.
"""
delay_samples = int(delay*SAMPLE_FREQUENCY)
z = zeros(delay_samples)
output = empty(len(orig_data), dtype=numpy.int16)
# Echo generation goes here
return output
########################################################################
def sin_sample(freq, amp, dur):
"""
sin_sample(freq, amp, dur)
This function returns a sine wave with frequencey freq, amplitude amp,
and duration dur (in seconds). The smplitude should be specified
with a range of 0 to 1 where 1 represents the maximal amplitude.
To obtain the actual amplitude in the sample use the WAVE_MAX value
to scale it to an appropriate value.
"""
output = empty(int(dur*SAMPLE_FREQUENCY), dtype=numpy.int16)
return output
########################################################################
def combine_mean(wavs):
"""
This function takes a list of data from different wave samples and
combines them into a single sound. All samples must have the same
length.
Recall that in python *wavs means the functions takes a variable
number of arguments. The arguments are packed into a tuple, which
can be iterated similarly to a list or array.
To calculate the combined wave, take the sum of each wave sample
divided by thenumber of wave samples (i.e. the mean).
"""
output = zeros(len(wavs[0]), dtype=numpy.int16)
return output
########################################################################
def silence(dur):
"""
silence(dur)
Return a sample with dur seconds of silence
"""
return zeros(int(dur*SAMPLE_FREQUENCY), dtype=numpy.int16)
########################################################################
def half_speed(data):
"""
This function takes an array of data and repeats each sample twice.
The result is that the original sound is effectively half the speed
of the original when played.
That is:
[x1,x2,x3,x4] => [x1,x1,x2,x2,x3,x3,x4,x4]
"""
result = empty(len(data)*2, dtype=numpy.int16)
return result
########################################################################
def combine_interleave(wavs):
"""
This function takes a list of waves that may have different lengths.
The resulting wave takes samples from the waves and interleaves them.
The resulting wave's length is equal to the length of the shortest
wave multiplied by the number of waves. That is, the waves are only
interleaved so long as there are more samples left in all waves.
For example:
[[x1,x2,x3,x4], [y1,y2,y3], [z1,z2,z3,z4,z5]] =>
[x1,y1,z1,x2,y2,z2,x3,y3,z3]
Because of the discontinuity this introduces into the waves, it is
normal to hear some high frequency noise. Also, when mixing more
than two waves in this way, the result will not resemble any of the
inputs very much.
"""
length = len(wavs[0])
result = empty(len(wavs)*length, dtype=numpy.int16)
return result