Category: Entertainment

Presentation Description

No description available.


Presentation Transcript

Automated Piano Music Player:

Automated Piano Music Player ENG 06, Section A02 Aldrin Agana and Jer -Yen Hsu

Reading the files:

Reading the files To read the file, first we prompt for the user’s input of file name(s) and save it as a string We used an if/then statement to detect if there’s a comma present. If there is (2 files), the input will be broken down into two names and each name will be read by the reader function. Example: music.txt , player.txt The reader function opens the name of the .txt file and scans it into a matrix as characters. Within the matrix, all Notes are stored in X Key, Y Octave, m Amplitude, k Duration, T file = input('Enter file name(s) that you wish to play.\n Ex:sample1,sample2\n ','s'); if sum(file==44) [junk col] = find(file==44); music1=file(1:col-1); [X Y m k T] = reader(music1); music2=file(col+1:end); [X2 Y2 m2 k2 T2] = reader(music2 ); [ X Y m k T]=reader(music) fid = fopen ( music,'r '); sheet = fscanf (fid,'%c', inf ); number=sheet(sheet>=45 & sheet<57); sheet=sheet( isletter (sheet)); X=sheet(1:2:end); Y=sheet(2:2:end); m=number(1:3:end); k=number(2:3:end); T=number(3:3:end );

Note Frequency:

Note Frequency Our first concern was creating a function to output the frequency of a given note Instead of typing out each individual frequency of all 88 keys of the piano, we used a formula Frequency = n is the nth key on a piano The function finds the key number of the given note specified by X, Y, and m and uses the formula to output the frequency function [ freq ] = freq ( X, Y, m ) m = str2num(m); switch X case 'C' note = 1; case 'D' note = 3; case 'E' note = 5; case 'F' note = 6; case 'G' note = 8; case 'A' note = 10; case 'B' note = 12; end note = note + 3; if Y == 'F' note = note - 1; elseif Y == 'S' note = note + 1; end note = note + (m-1)*12; freq = 440*2^((note-49)/12); end

Amplitude Vector:

Amplitude Vector The swave function creates the array of amplitudes and samples given frequency (f), note length (T), and beats per minute (BPM) First, we convert our string T to a type double Then, we find how many seconds are in a beat by dividing 60 by the BPM For T, 1 is a whole note, 2 is half, 4 is quarter, 8 is eighth, etc. 4/T equals how many beats are there We then create a time vector with length equal to the appropriate number of samples The vector for the tone equals sin(2*f*pi*t) function [ waveform sample] = swave ( f, T, BPM, sample ) T = str2num(T); beat = 60/BPM ; T = 4/T; t = linspace (0, beat*T, 44100*beat*T+1)'; waveform = sin(f*2*pi*t ); end

Attack and Decay:

Attack and Decay We created a function to create an attack and decay vector that can be multiplied to our amplitude vector We utilized the single-pole filter explained by P. De Leon in his paper “ Computer Music in Undergraduate Digital Signal Processing”: a ( n ) = a ˆ g + (1- g ) a ( n -1 ) We played around with the target and gain numbers to create a sound envelope similar to that of an actual piano


Compiler In the compiler function, we put all aspects of the sound together. First, we find the frequency of the note. Since higher frequencies sound louder and lower frequencies sound more quiet, we adjust notes with higher frequencies by multiplying its amplitude by ¾ for every octave it is above middle C. Then, we create a amplitude vector of the note. We create an attack and decay vector. Next, we multiply our original vector by the attack/decay vector and specified amplitude coefficient W e then normalize the vector so all values are within -1 and 1 by diving all values by the maximum value After its normalized, the amplitude adjustment is added Finally we concatenate the vectors into an existing matrix. function [ junk ] = compiler( X, Y, m, k, T, BPM, sample) f = freq (X, Y, m); if f>523 adjust = (3/4)^(523/f); elseif f<523 adjust = (5/4)^(f/523); else adjust = 1; end [x sample]= swave (f, T, BPM, sample); a = x; adsr1 = adsr (a, adsrtype ); amp = k/8; a = a.*adsr1*amp; a = adjust*a; junk = [ sample;a ]; end

Player (compiling):

Player (compiling) The purpose of compiler is to compile all the sound vectors together. Each iteration produces all the vectors for a specific note and tacks it on after the vectors of the previous notes by recycling “sample” Sample is set as a 1x1 matrix containing a 0 so that it can serve as a base for the concatenating process At the end of the iterations, matrix “sample” will contain a 0 followed by all the vectors for music file 1, and matrix “sample2” will have the same for music file 2 sample=[0]; sample2=[0]; length=max(size(X )); for i=1:length [sample] = compiler(X(i),Y(i),m(i),k(i),T(i), BPM,sample , adsrtype ); end length=max(size(X2)); for i=1:length [sample2] = compiler(X2(i),Y2(i),m2(i),k2(i),T2(i),BPM,sample2, adsrtype ); end

Player (padding):

Player (padding) For the two music files to be played at the same time, they have to be combined into one matrix with two columns. In order to concatenate the two matrices containing all the vectors of each music file, the dimensions of the matrices have to match. We padded the shorter matrix with 0’s to match dimensions with the longer matrix. if max(size(sample ))>max(size(sample2)) sample2(max(size(sample)))=[0]; elseif max(size(sample))<max(size(sample2)) sample(max(size(sample2)))=[0 ]; end sample = [sample sample2 ];

Player (accents):

Player (accents) Once the loops is done compiling all the sound vectors, we can use its length to determine different statistics of the song To create emphasis on first and third beats, we used a for loop to find the indices of the samples corresponding to the beats and multiply them by 1.5. Again, we use the technique of concatenating within iterations. Lastly, the emphasis is only applied if the user chooses “yes” samplesize = max(size(sample))-1; measures = round(( samplesize /44100)/(4*60/BPM)); samplespermeasure = samplesize /measures; samplesperbeat =round( samplespermeasure /4); emphasis=ones(size(sample )); for i=0:measures-1 ; first= samplespermeasure .*i+1:samplespermeasure.* i+samplesperbeat ; third= samplespermeasure .* i+samplesperbeat *2:samplespermeasure.* i+samplesperbeat *3; temp1=[temp1 first]; temp2=[temp2 third]; end first=temp1(2:end); third=temp2(2:end); emphasis([first third],:)=emphasis([first third],:)*1.5; if strcmpi ( accent,'yes ') sample=sample.*emphasis; elseif strcmpi ( accent,'no ') end

Player (methodology):

Player (methodology) User can choose whether to play continuously or by each measure. Option of measure by measure plays and graphs only one measure at a time and is controlled by a press of ENTER method = input('Do you want to play the music continuously or measure-by-measure? ','s'); start=2; if strcmpi ( method,'continuously ') || strcmpi ( method,'continuous ') sound(sample,44100) plot(sample) else for i=1:measures plot( start:samplespermeasure *i+1,sample(( start:samplespermeasure *i+1),:)) axis([0 samplesize -2 2]) hold on sound(sample(( start:samplespermeasure *i+1),:),44100) start= samplespermeasure *i+1; input('Press ENTER to continue to the next measure') end end The song starts from sample index 2 because index 1 is 0, the base. Using the value of samplespermeasure in a loop, we set the start of each measure as the end of the last measure.

Using The Program:

Using The Program When the program is started, the user is prompted to choose from different playing options The user first enters the filename(s) of the ASCII files which contain the music data To play with two hands, the user simply enters in two filenames separated by a comma The user is then prompted for continuous or measure-by-measure play, tempo, whether to add emphasis on the first and third beats, and which attack and decay scheme to be used

Playing a Song:

Playing a Song When a song is played, it can be played in two ways, measure-by-measure or continuously. In the measure-by-measure method, a measure is played and then a plot of the waveform is shown. (top) In the continuous method, the entire song is played and a waveform of it is shown. (bottom)

authorStream Live Help