This was the code I was using in playgrounds.
import PlaygroundSupport
import AudioToolbox
PlaygroundPage.current.needsIndefiniteExecution = true
postfix operator ♭
postfix operator ♯
@propertyWrapper
struct Pitch {
var hertz: Double
var wrappedValue: Double {
get { hertz }
set { hertz = newValue }
}
// Increases the pitch by 12th parts
static postfix func ♯(num: Pitch) -> Pitch {
return Pitch(hertz: num.hertz * 1.0594630943592953)
}
// Decreases the pitch by 12th parts
static postfix func ♭(num: Pitch) -> Pitch {
return Pitch(hertz: num.hertz * 0.9438743126816935)
}
}
@propertyWrapper
struct Note {
var number: Int
var wrappedValue: Int {
get { number }
set { number = newValue }
}
static postfix func ♯(num: Note) -> Note {
return Note(number: num.number+1)
}
static postfix func ♭(num: Note) -> Note {
return Note(number: num.number+1)
}
}
postfix operator ♪
extension Pitch {
// Convert a pitch to a MIDI note number
static postfix func ♪(num: Pitch) -> Note {
return Note(number: Int(round(12 * log2(num.wrappedValue / 440.0))))
}
}
enum MIDI {
enum Notes {
// C4
static let C = Note(number: 60)
// D
static let D = Note(number: 62)
// E
static let E = Note(number: 64)
// F
static let F = Note(number: 65)
// G
static let G = Note(number: 67)
// A
static let A = Note(number: 69)
// B
static let B = Note(number: 71)
}
}
@resultBuilder
enum NoteBuilder{
static func buildBlock(_ notes: Note...) -> [MIDINoteMessage] {
notes.map {
MIDINoteMessage(channel: 1,
note: UInt8($0.number),
velocity: 64,
releaseVelocity: 0,
duration: 1 )
}
}
}
func 𝄞(@NoteBuilder _ makeNotes: () ->[MIDINoteMessage])-> MusicSequence {
var sequence : MusicSequence? = nil
var musicSequence = NewMusicSequence(&sequence)
var track : MusicTrack? = nil
var musicTrack = MusicSequenceNewTrack(sequence!, &track)
var time = MusicTimeStamp(1.0)
for n in makeNotes() {
var note = n
musicTrack = MusicTrackNewMIDINoteEvent(track!, time, ¬e)
time += 0.3
}
return sequence!
}
let A = MIDI.Notes.A
let B = MIDI.Notes.B
let C = MIDI.Notes.C
let D = MIDI.Notes.D
let E = MIDI.Notes.E
let F = MIDI.Notes.F
let G = MIDI.Notes.G
var musicPlayer : MusicPlayer? = nil
var player = NewMusicPlayer(&musicPlayer)
var 📲🎶 = 𝄞{
F; C; A♯; C; F
G; G; A♯; C; C; A♯; G; C; F; C; A♯; C; F
G; G; A♯; C; C; A♯; G; C; F; C; A♯; C; F
G; G; A♯; C; C; A♯; G; C; F; C; A♯; C; F
}
player = MusicPlayerSetSequence(musicPlayer!, 📲🎶)
player = MusicPlayerStart(musicPlayer!)
which gives you
I know it doesn't sound good (to be fair to me, Im trying to learn this stuff
)
But it's really fun to play with (on playgrounds on macOS synths a piano sound which sounds a lot better, I don't know what instrument iPad playgrounds is modelled on)
I know it sounds gimmicky to be working on a Music DSL that resembles music notation, since there aren't any musical symbols on mechanical keyboards, this entire musical symbol business on a hardware keyboard doesn't make sense.
But iPad's keyboard is virtual and since this is equally happy on a playground on the iPad as it is on the Mac, why not take advantage of the virtual keyboard?
So the next 2 things I would like to look in to are
- extracting this out to a package on it's own.
- A custom keyboard for iPad with
𝄞, ♯,♭ and other musical symbols.
But the code above is quite literally the sum of all Swift code I've ever written, so there's a lot to learn.
That's on top of this thing actually was born out of me trying to teach my self music theory.
I'm sure to people who've done a fair bit of Swift this is second nature, but I have to keep checking the language guide for everything
so on the one side I have the Swift Language Guide on the other side I have music theory books.
I'm learning so much from this.
Would very much appreciate any guidance or help folks may be able to offer either about swift or music theory 
Hope this is helpful to someone...