Reading: Ch. 14
There are also two sample files providing instrument samples for a single note (piano, and violin).
A more complex one (LetItBe.mid) is a "format 1" having multiple, synchronous tracks.
We will not consider the more complex "format 2" files, that use asynchronious tracks.
[samples freq bitsPerSample aux] = wavread(filename)
wavwrite(samples, filename)
wavwrite(samples, freq, filename)
wavwrite(samples, freq, bitsPerSample, filename)
wavplay(samples, freq)
wavplay(samples, freq, 'async') % call returns even while sound is still playing
wavplay(samples, freq, 'sync') % call waits until sound is complete before returning
function plotStereo(y, fs)
subplot(2,1,1);
x = linspace(0, length(y)/fs, length(y));
plot(x,y(:,1), 'b'); % plot in blue
ylabel('Left');
xlabel('seconds');
axis([0 length(y)/fs -1 1]);
grid on;
subplot(2,1,2);
plot(x,y(:,2), 'r'); % plot in red
ylabel('Right');
xlabel('seconds');
axis([0 length(y)/fs -1 1]);
grid on;
We examined how to develop pure tones of a given frequency as a cosine wave, or to take an existing instrument waveform and to alter its frequency to produce notes at other pitches. We then examined high-level approaches to representing songs as a series of notes, or as a composition of overlayed notes.
All of our full source code is available at the link near the top of this page. But a highlight of the signatures we used are as follows.
function hz = midiFreq(note)
% Returns the frequency for a given note on midi scale.
% For example, MIDI 60 is middle C (261.626HZ)
function Y = pureTone(freq, duration, amplitude, fs)
% Generates a cosine wave representing a pure tone.
% freq specifies the audio frequency (in Hertz)
% duration specifies the length of the tone (in seconds)
% amplitude of sound (with 127 being the loudest)
% fs desginates the playback frequency (samples per second)
% (fs is 8000 by default)
function Y = ramp(Y, leadTime, trailTime, fs)
% linear ramps the given signal.
% Y can be a row vector or column vector.
% leadTime (in seconds) will be ramped from zero to full attentuation
% trailTime (in seconds) will be ramped from full attentuation to zero
% fs is sample rate
function Y = buildNote(freq, duration, amplitude, fs, instr)
% Produces waveform for single note.
% freq specifies the audio frequency (in Hertz)
% duration specifies the length of the tone (in seconds)
% amplitude of sound (with 127 being the loudest)
% fs desginates the playback frequency (samples per second)
% instr is a waveform for the instrument (at 260HZ and 44100fs)
% (if not given, pureTone will be formed)
Our goal is to write a MATLAB program that can process authentic midi files and produce a sound wave for the music (at least a simplified one that ignores changes in instruments).
This lead to the following additional functionality.
function song = parseMidi(filename)
% returns a song structure with the following fields
% format (0=single track, 1=multiple syncronized tracks, 2=multiple asyncronous)
% ticksPerQuarter tick units per quarter note
% tracks cell array of individual tracks, each of which is an array
% of "event" structures.
%
% Each event structure has the following fields
% delta the lead time (measured in ticks) between preceding event and this
% status a code for the event type (e.g., 8 = NoteOff, 9 = NoteOn)
% channel what channel should the note be played on
% note the midi number for the note
% amplitude the midi number for the note
function Y = composeMidiSong(song, tempo, fs)
% Create a wave for the given song structure.
% tempo is measured in beats per second
% (assume that a quarter note is one beat)
% fs is the desired sample rate for the waveform