An AFNote in Objective-C
Intro
I'm porting an Audiofile project to Objective-C and I've created an AFNote
class. The idea is that AFNote objects will be the primitive building block with
which developers can create AFInterval, AFChord, and AFScale objects.
The files
First let's start with the files and then an explanation. For now this is just one class so there is an AFNote.h and an AFNote.m file.
AFNote.h
#import <Foundation/Foundation.h>
@interface AFNote : NSObject
@property NSNumber *pitch;
@property NSNumber *octave;
@property NSNumber *noteType;
@property NSNumber *key;
@property NSNumber *beatsPerMinute;
// make the following properties readonly
@property NSNumber *frequency;
@property NSArray *frequencies;
@property NSNumber *duration;
- (id) initWithPitch:(NSNumber *) pitch andOctave:(NSNumber *) octave andAFNoteType:(NSNumber *) noteType andKey:(NSNumber *) key andBeatsPerMinute:(NSNumber *) beatsPerMinute;
@end
AFNote.m
#import "AFNote.h"
@implementation AFNote
-(id) initWithPitch:(NSNumber *)pitch andOctave:(NSNumber *)octave andAFNoteType:(NSNumber *)noteType andKey:(NSNumber *)key andBeatsPerMinute:(NSNumber *)beatsPerMinute
{
if (self = [super init])
{
[self setPitch:pitch];
[self setOctave:octave];
[self setNoteType:noteType];
[self setKey:key];
[self setBeatsPerMinute:beatsPerMinute];
[self setFrequencies:[NSArray arrayWithObjects:@"27.5", @"29.1352", @"30.8677", @"32.7032", @"34.6478", @"36.7081", @"38.8909", @"41.2034", @"43.6535", @"46.2493", @"48.9994", @"51.9131", @"55", @"58.2705", @"61.7354", @"65.4064", @"69.2957", @"73.4162", @"77.7817", @"82.4069", @"87.3071", @"92.4986", @"97.9989", @"103.826", @"110", @"116.541", @"123.471", @"130.813", @"138.591", @"146.832", @"155.563", @"164.814", @"174.614", @"184.997", @"195.998", @"207.652", @"220.000", @"233.082", @"246.942", @"261.626", @"277.183", @"293.665", @"311.127", @"329.628", @"349.228", @"369.994", @"391.995", @"415.305", @"440", @"466.164", @"493.883", @"523.251", @"554.365", @"587.330", @"622.254", @"659.255", @"698.456", @"739.989", @"783.991", @"830.609", @"880", @"932.328", @"987.767", @"1046.50", @"1108.73", @"1174.66", @"1244.51", @"1318.51", @"1396.91", @"1479.98", @"1567.98", @"1661.22", @"1760", @"1864.66", @"1975.53", @"2093", @"2217.46", @"2349.32", @"2489.02", @"2637.02", @"2793.83", @"2959.96", @"3135.96", @"3322.44", @"3520", @"3729.31", @"3951.07", @"4186.01", nil]
];
[self setFrequency:[NSNumber numberWithFloat:[[[self frequencies] objectAtIndex:[[self octave] intValue] * 12 + [[self pitch] intValue]] floatValue]]];
[self setDuration:[NSNumber numberWithFloat:60 / [[self beatsPerMinute] floatValue]]];
}
return self;
}
@end
Custom init method
I created a custom init method which sets up the AFNote with the values that we need:
- (id) initWithPitch:(NSNumber *) pitch andOctave:(NSNumber *) octave andAFNoteType:(NSNumber *) noteType andKey:(NSNumber *) key andBeatsPerMinute:(NSNumber *) beatsPerMinute;
Sidenote
I have been finding Objective-C a challening syntax to grasp. It's beginning to sink in but it took a while to be able to wade through the nested square brackets. But this method name shows what I think is an extremely cool feature of the language once your brain can casually read it. And that feature is how the method name is self documenting with regards to parameters.
You can perhaps imagine something like this in Javascript:
function AFNote(pitch, octave, noteType, key, beatsPerMinute);
The problem is that when a developer creates an instance of an AFNote Object she
needs to be aware of the AFNote constructor method's signature.
Objective-C solves this problem by including part of the name for each argument.
So in my custom init method you can see that it requires a price, octave,
noteType, key, and beatsPerMinute.
Now back to our regularly scheduled program...
The Properties
An AFNote object has several properties:
key
To set the key for an AFNote pass an NSNumber between -7 and 7 into the settings object. The entire circle of fifths. 0 = C, -7 = C flat, and 7 = C sharp.
octave
There are 8 octaves on the keyboard.
To set an AFNote's octave pass an NSNumber with a value between 0–8.
pitch
Each octave is 12 notes. For example 1 octave in the key of C is: C, C#, D, D#, E, F, F#, G, G#, A, A#, B. Between one
note and the next is called a half-step. Therefore to both set an AFNote's pitch pass an NSNumber with a value between 0–11.
Remember that all counting is zero indexed and starts with 0. So in the key of C—C would be 0 and the B nearly one octave higher would be 11.
noteType
Different types of notes. 1 for whole note, 2 for half note, 4 for
quarter note, and 8 for eighth notes etc.
beatsPerMinute
The number of beats per minute which is used to calculate the duration of each note.
frequency
The frequency of an AFNote is a combination of it’s octave property which tells which octave the note is in (0–8) as well as the pitch property which tells the note’s location within the octave.
frequencies
This is an NSArray of NSString objects which are the frequencies of the 88
keys on a keyboard.
duration
The length a note should sound. This is calculated by dividing 60 seconds by the number of beats per minute.
Create an AFNote Object
AFNote *myAFNote = [[AFNote alloc] initWithPitch:[NSNumber numberWithInt:3] andOctave:[NSNumber numberWithInt:0] andNoteType:[NSNumber numberWithInt:8] andKey:[NSNumber numberWithInt:0] andBeatsPerMinute:[NSNumber numberWithInt:120]];
Thoughts
I realize that frequencies shouldn't be a public property which can be set
with [AFNote setFrequencies]. This is obviously a fail because someone could
destroy the NSArray of frequencies.
There are actually a few properties which I'd like to make readonly but I'm
not sure the exact sytax so I'm going with this for now.
Those properties are:
@property NSNumber *frequency;
@property NSArray *frequencies;
@property NSNumber *duration;
Thanks for reading! Follow me on Twitter and/or G+ for more.
See something wrong or got something to add/change? Fork this git repo and send me a pull request
If you particularly enjoy my work, I appreciate donations given with Gitcoin.co