ucsb-cs56-projects / cs56-music-basic-synthesis-demo

-
0 stars 5 forks source link

Refactor the melody format code. #19

Open pconrad opened 11 years ago

pconrad commented 11 years ago

~depends #18

Adjust all current code to support a new melody format.

Melody files should be in the format:

Pitch should either be a frequency in Hertz, OR a note name from the "scientific name" column of the chart on this page, OR Midi value specified as M1 M2 M3, etc. The code should check the format of the input string (perhaps against a regular expression?) to see which format is being used. http://en.wikipedia.org/wiki/Piano_key_frequencies Use b for flat and # for sharp. Note that these frequencies can be calculated with a formula involving the 2 to the 1/12 power---you do not need to hard code them. Duration should be a fraction of a beat, and the "tempo" in beats per minute should be used to determine the length of a beat. At 60 beats per minute, each beat is 1 second. At 120 beats per minute, each beat is 1/2 second. At 30 beats per minute, each beat is 2 seconds, etc. Then for loudness, let the 1.0 be a relative scale where 1.0 is the maximum volume. Multiply the envelope volumes by the note volume to get the actual volume used to play the note. Add an additional control to both the command line and GUI programs which is an other "overall" volume scaling factor applied to EVERY volume, between 0 and 1. REASON: to avoid clipping. This allows you to specify notes of maximum volume as 1.0 rather than 0.95 or 0.99---and just put an "overall" volume scale of 0.95 or 0.99 that adjusts the volume of every note. ~estimated: 300
pconrad commented 10 years ago

@rtwaltman and @dwang68

dwang68 commented 10 years ago

@pconrad commenting from @dwang68 account...

The missing line, I think is this:

pitch duration loudness pitch duration loudness pitch duration loudness pitch duration loudness pitch duration loudness pitch duration loudness etc...

dwang68 commented 10 years ago

So,for example: frere jacques might be:

c4   1    0.5
d4   1    0.5
e4   1    0.5
c4   1    0.5 
c4   1    0.5
d4   1    0.5
e4   1    0.5
c4    1    0.5
e4   1     0.6
f4   1     0.6
g4   2     0.6
e4  1      0.7
f4   1      0.7
g4  2      0.7
g4  0.5     1
a4  0.5     1
g4   0.5    1
f4   0.5     1
e4   1        1
c4    1       1
g4  0.5      0.25
a4  0.5      0.25
g4   0.5     0.25
f4   0.5      0.25
e4   1        0.25
c4    1       0.25
c4  1         0.6
g3  1         0.6
c4 2          0.6
c4  1         0.4
g3  1         0.3
c4 2          0.2
dwang68 commented 10 years ago

@pconrad We are confused about the where to implement the master amplitude. I am wondering if the amplitude in the ADSREnvelopedContinuousSound defines the amplitude of the envelope at time t as it gets called in the class EnvelopedSound.java

for(; i<samples; i++){ amp=generateAmplitude(t,amp); audioData[i]=(byte)((127)_generateWave(t)_amp); t+=1.0/(double)this.sampleRate;
}

//And the sustain amplitude is multiplied by the amp of the note a.setSustainAmplitude(amp*sustainamp);

//But the amplitude of the ADSREnvelopedContinuousSound gets the amplitude of the note new ADSREnvelopedContinuousSound(freq, amp, a, 44100, d);

Can you explain the relations of those amplitude and where should we implement the master amplitude? Thanks a lot!

rtwaltman commented 10 years ago

@dwang68 @bronhuston I'm thinking that we can just do a simple multiplier on the note volume, which we get while reading in from a .txt file. So if we just multiply it by some GUI-changeable variable called masterVolume, then each note should be adjusted to the 0->.95 scale.

To be specific, in createMelodyFromFile(), we split every line of our .txt: pitch duration loudness and get the appropriate freq, duration, volume

Our 'loudness' or 'volume' string, which is splitline[2], gets parsed to a double and then set to a function variable volume, which gets passed to a Note constructor with: "m.add(new Note(freq,duration,volume));". So this adds the fully built notes from the line of text to our melody, which gets played later. So I'm thinking that our masterVolume should EITHER be in Note.java and when the instance variables get set by the constructor, we simply multiply the sent in volume by our masterVolume and then set it to the instance variable volume OR in Melody.java and the multiplication is done before the constructor call.

Then, the sustain amplitude will be multiplied by the new adjusted note volume on a scale of 0-.95 and everything already written should be working properly (at least I think). That way, we're not ever using a 1 amplitude note anywhere

bronhuston commented 10 years ago

@rtwaltman This sounds like a good plan so far.

Personally, I think that it makes the most sense to make the MasterVolume in the Note.java class because that is where the actual note is created.

The melody.java file primarily deals with creating the list of notes for a melody from some specified input(txt file). I think it makes the most sense to have the Melody.java file control how the list of notes is created from various input formats, while the Note.java file deals with actually creating each note and ensuring it has the correct amplitude, volume, etc.

It seems like this is how you are planning on handling it, so it sounds like you're definitely on the right track!

rtwaltman commented 10 years ago

@bronhuston

I've implemented the volume label, text field, and slider for our masterVolume, but I'm to the point where I'm unsure of how to get the value of our masterVolume into every Note class that gets created. I was thinking of trying to make it a global sort of variable that could always be accessed and used, such as this:

public class Globals {
    public static double masterVolume; //set this to our slider masterVolume
}

Then, whenever we make the note amplitude, we do something like amplitude *= G.masterVolume;, where G is an instance of Globals used just to get the variable.

I see two potential problems with this, however.

  1. Setting masterVolume every time the volume slider is moved
  2. It may be 'bad' code, as java doesn't exactly encourage constants.

Looking at the code, I'm having a hard time tracing through and finding where and when the GUI builds the notes. I've been trying to decode the AudioFormat, SourceDataLine, and AudioSystem java classes to understand what's actually happening with the button listeners. As far as I can tell, AudioSystem builds a playable sound line, SourceDataLine, by using AudioFormat. And then that SourceDataLine is used to create an ADSREnvelopedContinuousSound instance, which calls the EnvelopedSound constructor inside of its constructor...and this is where I am lost. It appears Note is never even used for the melodyGUI. There's amplitudes being built inside of the EnvelopedSound, but as far as I can tell, Note is never used. Are these the amplitudes being built per note?

I'll definitely be bombarding Professor Conrad at office hours.

rtwaltman commented 10 years ago

We basically have two things to implement:

  1. Master volume control on command line .txt melody playing
  2. Master volume control in melodyGUI

The latter of which is abstracted away from using the Note class.

bronhuston commented 10 years ago

@rtwaltman In the case of the MelodyGui code, the Note class is sort of used indirectly. By this I mean that since the MelodyGUI uses the Melody class and the Melody class uses the note class, the MelodyGui class sort of uses the note class.

By changing how certain aspects of the Note class are handled, you change the contents of the Melody.

The melody class then handles the actual playing of the note through the creation of the ADSREnvelope etc.

In the Note class has values for the freq, duration and volume of each note, and the Melody class sets the amplitude to be equal to the the (notes volume)*(the inputed amp of the envelope) for each note.

rtwaltman commented 10 years ago

@bronhuston I see. I was getting caught up on the details of the things that I don't understand and wasn't looking past them. Thanks for pushing me in the right direction!

erdinckorpeoglu commented 10 years ago

Duration of notes requires more work.