diff --git a/app/src/main/java/com/lukas/music/instruments/Instrument.kt b/app/src/main/java/com/lukas/music/instruments/Instrument.kt index 72db3a1..811d16c 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -1,6 +1,7 @@ package com.lukas.music.instruments import com.lukas.music.databinding.FragmentInstrumentBinding +import com.lukas.music.song.note.Note abstract class Instrument(private var name: String) { private var active = false @@ -17,7 +18,7 @@ binding.activeSwitch.isChecked = active } - abstract fun startNote(frequency: Double) + abstract fun startNote(note: Note) abstract fun changeActive(newActive: Boolean) companion object { diff --git a/app/src/main/java/com/lukas/music/instruments/Instrument.kt b/app/src/main/java/com/lukas/music/instruments/Instrument.kt index 72db3a1..811d16c 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -1,6 +1,7 @@ package com.lukas.music.instruments import com.lukas.music.databinding.FragmentInstrumentBinding +import com.lukas.music.song.note.Note abstract class Instrument(private var name: String) { private var active = false @@ -17,7 +18,7 @@ binding.activeSwitch.isChecked = active } - abstract fun startNote(frequency: Double) + abstract fun startNote(note: Note) abstract fun changeActive(newActive: Boolean) companion object { diff --git a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt index d7460d4..1b53d5d 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -1,11 +1,12 @@ package com.lukas.music.instruments +import com.lukas.music.song.note.Note + class MonoInstrument(name: String) : Instrument(name) { private val internalInstrument = InternalInstrument() - override fun startNote(frequency: Double) { - println("note $frequency") - internalInstrument.startNote(frequency) + override fun startNote(note: Note) { + internalInstrument.startNote(note.frequency) } override fun changeActive(newActive: Boolean) { diff --git a/app/src/main/java/com/lukas/music/instruments/Instrument.kt b/app/src/main/java/com/lukas/music/instruments/Instrument.kt index 72db3a1..811d16c 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -1,6 +1,7 @@ package com.lukas.music.instruments import com.lukas.music.databinding.FragmentInstrumentBinding +import com.lukas.music.song.note.Note abstract class Instrument(private var name: String) { private var active = false @@ -17,7 +18,7 @@ binding.activeSwitch.isChecked = active } - abstract fun startNote(frequency: Double) + abstract fun startNote(note: Note) abstract fun changeActive(newActive: Boolean) companion object { diff --git a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt index d7460d4..1b53d5d 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -1,11 +1,12 @@ package com.lukas.music.instruments +import com.lukas.music.song.note.Note + class MonoInstrument(name: String) : Instrument(name) { private val internalInstrument = InternalInstrument() - override fun startNote(frequency: Double) { - println("note $frequency") - internalInstrument.startNote(frequency) + override fun startNote(note: Note) { + internalInstrument.startNote(note.frequency) } override fun changeActive(newActive: Boolean) { diff --git a/app/src/main/java/com/lukas/music/song/Chord.kt b/app/src/main/java/com/lukas/music/song/Chord.kt index 0b224db..c3328f1 100644 --- a/app/src/main/java/com/lukas/music/song/Chord.kt +++ b/app/src/main/java/com/lukas/music/song/Chord.kt @@ -1,3 +1,3 @@ package com.lukas.music.song -class Chord(val root: Double) \ No newline at end of file +class Chord(val note: Int, val chordType: ChordType) \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/Instrument.kt b/app/src/main/java/com/lukas/music/instruments/Instrument.kt index 72db3a1..811d16c 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -1,6 +1,7 @@ package com.lukas.music.instruments import com.lukas.music.databinding.FragmentInstrumentBinding +import com.lukas.music.song.note.Note abstract class Instrument(private var name: String) { private var active = false @@ -17,7 +18,7 @@ binding.activeSwitch.isChecked = active } - abstract fun startNote(frequency: Double) + abstract fun startNote(note: Note) abstract fun changeActive(newActive: Boolean) companion object { diff --git a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt index d7460d4..1b53d5d 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -1,11 +1,12 @@ package com.lukas.music.instruments +import com.lukas.music.song.note.Note + class MonoInstrument(name: String) : Instrument(name) { private val internalInstrument = InternalInstrument() - override fun startNote(frequency: Double) { - println("note $frequency") - internalInstrument.startNote(frequency) + override fun startNote(note: Note) { + internalInstrument.startNote(note.frequency) } override fun changeActive(newActive: Boolean) { diff --git a/app/src/main/java/com/lukas/music/song/Chord.kt b/app/src/main/java/com/lukas/music/song/Chord.kt index 0b224db..c3328f1 100644 --- a/app/src/main/java/com/lukas/music/song/Chord.kt +++ b/app/src/main/java/com/lukas/music/song/Chord.kt @@ -1,3 +1,3 @@ package com.lukas.music.song -class Chord(val root: Double) \ No newline at end of file +class Chord(val note: Int, val chordType: ChordType) \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/ChordType.kt b/app/src/main/java/com/lukas/music/song/ChordType.kt new file mode 100644 index 0000000..a68adb6 --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/ChordType.kt @@ -0,0 +1,7 @@ +package com.lukas.music.song + +enum class ChordType(private val notes: Array) { + Major(arrayOf(0, 4, 7)), + Minor(arrayOf(0, 3, 7)), + ; +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/Instrument.kt b/app/src/main/java/com/lukas/music/instruments/Instrument.kt index 72db3a1..811d16c 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -1,6 +1,7 @@ package com.lukas.music.instruments import com.lukas.music.databinding.FragmentInstrumentBinding +import com.lukas.music.song.note.Note abstract class Instrument(private var name: String) { private var active = false @@ -17,7 +18,7 @@ binding.activeSwitch.isChecked = active } - abstract fun startNote(frequency: Double) + abstract fun startNote(note: Note) abstract fun changeActive(newActive: Boolean) companion object { diff --git a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt index d7460d4..1b53d5d 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -1,11 +1,12 @@ package com.lukas.music.instruments +import com.lukas.music.song.note.Note + class MonoInstrument(name: String) : Instrument(name) { private val internalInstrument = InternalInstrument() - override fun startNote(frequency: Double) { - println("note $frequency") - internalInstrument.startNote(frequency) + override fun startNote(note: Note) { + internalInstrument.startNote(note.frequency) } override fun changeActive(newActive: Boolean) { diff --git a/app/src/main/java/com/lukas/music/song/Chord.kt b/app/src/main/java/com/lukas/music/song/Chord.kt index 0b224db..c3328f1 100644 --- a/app/src/main/java/com/lukas/music/song/Chord.kt +++ b/app/src/main/java/com/lukas/music/song/Chord.kt @@ -1,3 +1,3 @@ package com.lukas.music.song -class Chord(val root: Double) \ No newline at end of file +class Chord(val note: Int, val chordType: ChordType) \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/ChordType.kt b/app/src/main/java/com/lukas/music/song/ChordType.kt new file mode 100644 index 0000000..a68adb6 --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/ChordType.kt @@ -0,0 +1,7 @@ +package com.lukas.music.song + +enum class ChordType(private val notes: Array) { + Major(arrayOf(0, 4, 7)), + Minor(arrayOf(0, 3, 7)), + ; +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Note.kt b/app/src/main/java/com/lukas/music/song/Note.kt deleted file mode 100644 index e81286f..0000000 --- a/app/src/main/java/com/lukas/music/song/Note.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.lukas.music.song - -class Note \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/Instrument.kt b/app/src/main/java/com/lukas/music/instruments/Instrument.kt index 72db3a1..811d16c 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -1,6 +1,7 @@ package com.lukas.music.instruments import com.lukas.music.databinding.FragmentInstrumentBinding +import com.lukas.music.song.note.Note abstract class Instrument(private var name: String) { private var active = false @@ -17,7 +18,7 @@ binding.activeSwitch.isChecked = active } - abstract fun startNote(frequency: Double) + abstract fun startNote(note: Note) abstract fun changeActive(newActive: Boolean) companion object { diff --git a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt index d7460d4..1b53d5d 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -1,11 +1,12 @@ package com.lukas.music.instruments +import com.lukas.music.song.note.Note + class MonoInstrument(name: String) : Instrument(name) { private val internalInstrument = InternalInstrument() - override fun startNote(frequency: Double) { - println("note $frequency") - internalInstrument.startNote(frequency) + override fun startNote(note: Note) { + internalInstrument.startNote(note.frequency) } override fun changeActive(newActive: Boolean) { diff --git a/app/src/main/java/com/lukas/music/song/Chord.kt b/app/src/main/java/com/lukas/music/song/Chord.kt index 0b224db..c3328f1 100644 --- a/app/src/main/java/com/lukas/music/song/Chord.kt +++ b/app/src/main/java/com/lukas/music/song/Chord.kt @@ -1,3 +1,3 @@ package com.lukas.music.song -class Chord(val root: Double) \ No newline at end of file +class Chord(val note: Int, val chordType: ChordType) \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/ChordType.kt b/app/src/main/java/com/lukas/music/song/ChordType.kt new file mode 100644 index 0000000..a68adb6 --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/ChordType.kt @@ -0,0 +1,7 @@ +package com.lukas.music.song + +enum class ChordType(private val notes: Array) { + Major(arrayOf(0, 4, 7)), + Minor(arrayOf(0, 3, 7)), + ; +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Note.kt b/app/src/main/java/com/lukas/music/song/Note.kt deleted file mode 100644 index e81286f..0000000 --- a/app/src/main/java/com/lukas/music/song/Note.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.lukas.music.song - -class Note \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Song.kt b/app/src/main/java/com/lukas/music/song/Song.kt index a7c440a..9f9dd78 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -1,24 +1,35 @@ package com.lukas.music.song import com.lukas.music.instruments.Instrument +import com.lukas.music.song.note.Note +import com.lukas.music.song.note.NoteName class Song( - private val chordProgression: ChordProgression + private val root: Note, + private val chordProgression: ChordProgression, ) { fun step() { val chord = chordProgression.step() for (instrument in Instrument.instruments) { - instrument.startNote(chord.root) + instrument.startNote(root + chord.note) } } companion object { var currentSong = Song( + Note.of(NoteName.F, 4), ChordProgression( listOf( - Chord(130.82), Chord(164.82), Chord(174.62) + Chord(1, ChordType.Major), + Chord(6, ChordType.Major), + Chord(2, ChordType.Minor), + Chord(8, ChordType.Major), ) ) ) + + init { + println("root: ${currentSong.root.frequency}") + } } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/Instrument.kt b/app/src/main/java/com/lukas/music/instruments/Instrument.kt index 72db3a1..811d16c 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -1,6 +1,7 @@ package com.lukas.music.instruments import com.lukas.music.databinding.FragmentInstrumentBinding +import com.lukas.music.song.note.Note abstract class Instrument(private var name: String) { private var active = false @@ -17,7 +18,7 @@ binding.activeSwitch.isChecked = active } - abstract fun startNote(frequency: Double) + abstract fun startNote(note: Note) abstract fun changeActive(newActive: Boolean) companion object { diff --git a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt index d7460d4..1b53d5d 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -1,11 +1,12 @@ package com.lukas.music.instruments +import com.lukas.music.song.note.Note + class MonoInstrument(name: String) : Instrument(name) { private val internalInstrument = InternalInstrument() - override fun startNote(frequency: Double) { - println("note $frequency") - internalInstrument.startNote(frequency) + override fun startNote(note: Note) { + internalInstrument.startNote(note.frequency) } override fun changeActive(newActive: Boolean) { diff --git a/app/src/main/java/com/lukas/music/song/Chord.kt b/app/src/main/java/com/lukas/music/song/Chord.kt index 0b224db..c3328f1 100644 --- a/app/src/main/java/com/lukas/music/song/Chord.kt +++ b/app/src/main/java/com/lukas/music/song/Chord.kt @@ -1,3 +1,3 @@ package com.lukas.music.song -class Chord(val root: Double) \ No newline at end of file +class Chord(val note: Int, val chordType: ChordType) \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/ChordType.kt b/app/src/main/java/com/lukas/music/song/ChordType.kt new file mode 100644 index 0000000..a68adb6 --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/ChordType.kt @@ -0,0 +1,7 @@ +package com.lukas.music.song + +enum class ChordType(private val notes: Array) { + Major(arrayOf(0, 4, 7)), + Minor(arrayOf(0, 3, 7)), + ; +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Note.kt b/app/src/main/java/com/lukas/music/song/Note.kt deleted file mode 100644 index e81286f..0000000 --- a/app/src/main/java/com/lukas/music/song/Note.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.lukas.music.song - -class Note \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Song.kt b/app/src/main/java/com/lukas/music/song/Song.kt index a7c440a..9f9dd78 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -1,24 +1,35 @@ package com.lukas.music.song import com.lukas.music.instruments.Instrument +import com.lukas.music.song.note.Note +import com.lukas.music.song.note.NoteName class Song( - private val chordProgression: ChordProgression + private val root: Note, + private val chordProgression: ChordProgression, ) { fun step() { val chord = chordProgression.step() for (instrument in Instrument.instruments) { - instrument.startNote(chord.root) + instrument.startNote(root + chord.note) } } companion object { var currentSong = Song( + Note.of(NoteName.F, 4), ChordProgression( listOf( - Chord(130.82), Chord(164.82), Chord(174.62) + Chord(1, ChordType.Major), + Chord(6, ChordType.Major), + Chord(2, ChordType.Minor), + Chord(8, ChordType.Major), ) ) ) + + init { + println("root: ${currentSong.root.frequency}") + } } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/note/Note.kt b/app/src/main/java/com/lukas/music/song/note/Note.kt new file mode 100644 index 0000000..0005d13 --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/note/Note.kt @@ -0,0 +1,28 @@ +package com.lukas.music.song.note + +import kotlin.math.pow + +class Note(val id: Int) { + val noteName = NoteName.VALUES[id % NoteName.VALUES.size] + val octave = id / NoteName.VALUES.size - 1 + val frequency = noteName.baseFrequency * 2.0.pow(id / NoteName.VALUES.size - 5) + + operator fun plus(other: Int): Note { + if (other < 0 || other > 127) { + throw IllegalArgumentException("cannot add $other to note with id $id") + } + return NOTES[id + other] + } + + operator fun minus(other: Int): Note { + return this + (-other) + } + + companion object { + val NOTES = Array(128) { Note(it) } + + fun of(noteName: NoteName, octave: Int): Note { + return NOTES[NoteName.VALUES.size * (octave + 1) + noteName.index] + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/Instrument.kt b/app/src/main/java/com/lukas/music/instruments/Instrument.kt index 72db3a1..811d16c 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -1,6 +1,7 @@ package com.lukas.music.instruments import com.lukas.music.databinding.FragmentInstrumentBinding +import com.lukas.music.song.note.Note abstract class Instrument(private var name: String) { private var active = false @@ -17,7 +18,7 @@ binding.activeSwitch.isChecked = active } - abstract fun startNote(frequency: Double) + abstract fun startNote(note: Note) abstract fun changeActive(newActive: Boolean) companion object { diff --git a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt index d7460d4..1b53d5d 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -1,11 +1,12 @@ package com.lukas.music.instruments +import com.lukas.music.song.note.Note + class MonoInstrument(name: String) : Instrument(name) { private val internalInstrument = InternalInstrument() - override fun startNote(frequency: Double) { - println("note $frequency") - internalInstrument.startNote(frequency) + override fun startNote(note: Note) { + internalInstrument.startNote(note.frequency) } override fun changeActive(newActive: Boolean) { diff --git a/app/src/main/java/com/lukas/music/song/Chord.kt b/app/src/main/java/com/lukas/music/song/Chord.kt index 0b224db..c3328f1 100644 --- a/app/src/main/java/com/lukas/music/song/Chord.kt +++ b/app/src/main/java/com/lukas/music/song/Chord.kt @@ -1,3 +1,3 @@ package com.lukas.music.song -class Chord(val root: Double) \ No newline at end of file +class Chord(val note: Int, val chordType: ChordType) \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/ChordType.kt b/app/src/main/java/com/lukas/music/song/ChordType.kt new file mode 100644 index 0000000..a68adb6 --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/ChordType.kt @@ -0,0 +1,7 @@ +package com.lukas.music.song + +enum class ChordType(private val notes: Array) { + Major(arrayOf(0, 4, 7)), + Minor(arrayOf(0, 3, 7)), + ; +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Note.kt b/app/src/main/java/com/lukas/music/song/Note.kt deleted file mode 100644 index e81286f..0000000 --- a/app/src/main/java/com/lukas/music/song/Note.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.lukas.music.song - -class Note \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Song.kt b/app/src/main/java/com/lukas/music/song/Song.kt index a7c440a..9f9dd78 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -1,24 +1,35 @@ package com.lukas.music.song import com.lukas.music.instruments.Instrument +import com.lukas.music.song.note.Note +import com.lukas.music.song.note.NoteName class Song( - private val chordProgression: ChordProgression + private val root: Note, + private val chordProgression: ChordProgression, ) { fun step() { val chord = chordProgression.step() for (instrument in Instrument.instruments) { - instrument.startNote(chord.root) + instrument.startNote(root + chord.note) } } companion object { var currentSong = Song( + Note.of(NoteName.F, 4), ChordProgression( listOf( - Chord(130.82), Chord(164.82), Chord(174.62) + Chord(1, ChordType.Major), + Chord(6, ChordType.Major), + Chord(2, ChordType.Minor), + Chord(8, ChordType.Major), ) ) ) + + init { + println("root: ${currentSong.root.frequency}") + } } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/note/Note.kt b/app/src/main/java/com/lukas/music/song/note/Note.kt new file mode 100644 index 0000000..0005d13 --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/note/Note.kt @@ -0,0 +1,28 @@ +package com.lukas.music.song.note + +import kotlin.math.pow + +class Note(val id: Int) { + val noteName = NoteName.VALUES[id % NoteName.VALUES.size] + val octave = id / NoteName.VALUES.size - 1 + val frequency = noteName.baseFrequency * 2.0.pow(id / NoteName.VALUES.size - 5) + + operator fun plus(other: Int): Note { + if (other < 0 || other > 127) { + throw IllegalArgumentException("cannot add $other to note with id $id") + } + return NOTES[id + other] + } + + operator fun minus(other: Int): Note { + return this + (-other) + } + + companion object { + val NOTES = Array(128) { Note(it) } + + fun of(noteName: NoteName, octave: Int): Note { + return NOTES[NoteName.VALUES.size * (octave + 1) + noteName.index] + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/note/NoteName.kt b/app/src/main/java/com/lukas/music/song/note/NoteName.kt new file mode 100644 index 0000000..49c19b2 --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/note/NoteName.kt @@ -0,0 +1,32 @@ +package com.lukas.music.song.note + +import kotlin.math.pow + +const val A4 = 440.0 + +enum class NoteName(val index: Int, val asString: String) { + C(0, "C"), + Csharp(1, "C#"), + D(2, "D"), + Dsharp(3, "D#"), + E(4, "E"), + F(5, "F"), + Fsharp(6, "F#"), + G(7, "G"), + Gsharp(8, "G#"), + A(9, "A"), + Asharp(10, "A#"), + B(11, "B"), + ; + + val baseFrequency: Double = A4 * 2.0.pow(index.toDouble() / 12) + + operator fun plus(interval: Int): NoteName { + val resultPosition = (index + interval) % VALUES.size + return VALUES[resultPosition] + } + + companion object { + val VALUES = values() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/Instrument.kt b/app/src/main/java/com/lukas/music/instruments/Instrument.kt index 72db3a1..811d16c 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -1,6 +1,7 @@ package com.lukas.music.instruments import com.lukas.music.databinding.FragmentInstrumentBinding +import com.lukas.music.song.note.Note abstract class Instrument(private var name: String) { private var active = false @@ -17,7 +18,7 @@ binding.activeSwitch.isChecked = active } - abstract fun startNote(frequency: Double) + abstract fun startNote(note: Note) abstract fun changeActive(newActive: Boolean) companion object { diff --git a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt index d7460d4..1b53d5d 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -1,11 +1,12 @@ package com.lukas.music.instruments +import com.lukas.music.song.note.Note + class MonoInstrument(name: String) : Instrument(name) { private val internalInstrument = InternalInstrument() - override fun startNote(frequency: Double) { - println("note $frequency") - internalInstrument.startNote(frequency) + override fun startNote(note: Note) { + internalInstrument.startNote(note.frequency) } override fun changeActive(newActive: Boolean) { diff --git a/app/src/main/java/com/lukas/music/song/Chord.kt b/app/src/main/java/com/lukas/music/song/Chord.kt index 0b224db..c3328f1 100644 --- a/app/src/main/java/com/lukas/music/song/Chord.kt +++ b/app/src/main/java/com/lukas/music/song/Chord.kt @@ -1,3 +1,3 @@ package com.lukas.music.song -class Chord(val root: Double) \ No newline at end of file +class Chord(val note: Int, val chordType: ChordType) \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/ChordType.kt b/app/src/main/java/com/lukas/music/song/ChordType.kt new file mode 100644 index 0000000..a68adb6 --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/ChordType.kt @@ -0,0 +1,7 @@ +package com.lukas.music.song + +enum class ChordType(private val notes: Array) { + Major(arrayOf(0, 4, 7)), + Minor(arrayOf(0, 3, 7)), + ; +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Note.kt b/app/src/main/java/com/lukas/music/song/Note.kt deleted file mode 100644 index e81286f..0000000 --- a/app/src/main/java/com/lukas/music/song/Note.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.lukas.music.song - -class Note \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Song.kt b/app/src/main/java/com/lukas/music/song/Song.kt index a7c440a..9f9dd78 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -1,24 +1,35 @@ package com.lukas.music.song import com.lukas.music.instruments.Instrument +import com.lukas.music.song.note.Note +import com.lukas.music.song.note.NoteName class Song( - private val chordProgression: ChordProgression + private val root: Note, + private val chordProgression: ChordProgression, ) { fun step() { val chord = chordProgression.step() for (instrument in Instrument.instruments) { - instrument.startNote(chord.root) + instrument.startNote(root + chord.note) } } companion object { var currentSong = Song( + Note.of(NoteName.F, 4), ChordProgression( listOf( - Chord(130.82), Chord(164.82), Chord(174.62) + Chord(1, ChordType.Major), + Chord(6, ChordType.Major), + Chord(2, ChordType.Minor), + Chord(8, ChordType.Major), ) ) ) + + init { + println("root: ${currentSong.root.frequency}") + } } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/note/Note.kt b/app/src/main/java/com/lukas/music/song/note/Note.kt new file mode 100644 index 0000000..0005d13 --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/note/Note.kt @@ -0,0 +1,28 @@ +package com.lukas.music.song.note + +import kotlin.math.pow + +class Note(val id: Int) { + val noteName = NoteName.VALUES[id % NoteName.VALUES.size] + val octave = id / NoteName.VALUES.size - 1 + val frequency = noteName.baseFrequency * 2.0.pow(id / NoteName.VALUES.size - 5) + + operator fun plus(other: Int): Note { + if (other < 0 || other > 127) { + throw IllegalArgumentException("cannot add $other to note with id $id") + } + return NOTES[id + other] + } + + operator fun minus(other: Int): Note { + return this + (-other) + } + + companion object { + val NOTES = Array(128) { Note(it) } + + fun of(noteName: NoteName, octave: Int): Note { + return NOTES[NoteName.VALUES.size * (octave + 1) + noteName.index] + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/note/NoteName.kt b/app/src/main/java/com/lukas/music/song/note/NoteName.kt new file mode 100644 index 0000000..49c19b2 --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/note/NoteName.kt @@ -0,0 +1,32 @@ +package com.lukas.music.song.note + +import kotlin.math.pow + +const val A4 = 440.0 + +enum class NoteName(val index: Int, val asString: String) { + C(0, "C"), + Csharp(1, "C#"), + D(2, "D"), + Dsharp(3, "D#"), + E(4, "E"), + F(5, "F"), + Fsharp(6, "F#"), + G(7, "G"), + Gsharp(8, "G#"), + A(9, "A"), + Asharp(10, "A#"), + B(11, "B"), + ; + + val baseFrequency: Double = A4 * 2.0.pow(index.toDouble() / 12) + + operator fun plus(interval: Int): NoteName { + val resultPosition = (index + interval) % VALUES.size + return VALUES[resultPosition] + } + + companion object { + val VALUES = values() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt b/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt new file mode 100644 index 0000000..8714423 --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt @@ -0,0 +1,3 @@ +package com.lukas.music.song.voice + +class BassVoice \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/Instrument.kt b/app/src/main/java/com/lukas/music/instruments/Instrument.kt index 72db3a1..811d16c 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -1,6 +1,7 @@ package com.lukas.music.instruments import com.lukas.music.databinding.FragmentInstrumentBinding +import com.lukas.music.song.note.Note abstract class Instrument(private var name: String) { private var active = false @@ -17,7 +18,7 @@ binding.activeSwitch.isChecked = active } - abstract fun startNote(frequency: Double) + abstract fun startNote(note: Note) abstract fun changeActive(newActive: Boolean) companion object { diff --git a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt index d7460d4..1b53d5d 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -1,11 +1,12 @@ package com.lukas.music.instruments +import com.lukas.music.song.note.Note + class MonoInstrument(name: String) : Instrument(name) { private val internalInstrument = InternalInstrument() - override fun startNote(frequency: Double) { - println("note $frequency") - internalInstrument.startNote(frequency) + override fun startNote(note: Note) { + internalInstrument.startNote(note.frequency) } override fun changeActive(newActive: Boolean) { diff --git a/app/src/main/java/com/lukas/music/song/Chord.kt b/app/src/main/java/com/lukas/music/song/Chord.kt index 0b224db..c3328f1 100644 --- a/app/src/main/java/com/lukas/music/song/Chord.kt +++ b/app/src/main/java/com/lukas/music/song/Chord.kt @@ -1,3 +1,3 @@ package com.lukas.music.song -class Chord(val root: Double) \ No newline at end of file +class Chord(val note: Int, val chordType: ChordType) \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/ChordType.kt b/app/src/main/java/com/lukas/music/song/ChordType.kt new file mode 100644 index 0000000..a68adb6 --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/ChordType.kt @@ -0,0 +1,7 @@ +package com.lukas.music.song + +enum class ChordType(private val notes: Array) { + Major(arrayOf(0, 4, 7)), + Minor(arrayOf(0, 3, 7)), + ; +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Note.kt b/app/src/main/java/com/lukas/music/song/Note.kt deleted file mode 100644 index e81286f..0000000 --- a/app/src/main/java/com/lukas/music/song/Note.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.lukas.music.song - -class Note \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Song.kt b/app/src/main/java/com/lukas/music/song/Song.kt index a7c440a..9f9dd78 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -1,24 +1,35 @@ package com.lukas.music.song import com.lukas.music.instruments.Instrument +import com.lukas.music.song.note.Note +import com.lukas.music.song.note.NoteName class Song( - private val chordProgression: ChordProgression + private val root: Note, + private val chordProgression: ChordProgression, ) { fun step() { val chord = chordProgression.step() for (instrument in Instrument.instruments) { - instrument.startNote(chord.root) + instrument.startNote(root + chord.note) } } companion object { var currentSong = Song( + Note.of(NoteName.F, 4), ChordProgression( listOf( - Chord(130.82), Chord(164.82), Chord(174.62) + Chord(1, ChordType.Major), + Chord(6, ChordType.Major), + Chord(2, ChordType.Minor), + Chord(8, ChordType.Major), ) ) ) + + init { + println("root: ${currentSong.root.frequency}") + } } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/note/Note.kt b/app/src/main/java/com/lukas/music/song/note/Note.kt new file mode 100644 index 0000000..0005d13 --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/note/Note.kt @@ -0,0 +1,28 @@ +package com.lukas.music.song.note + +import kotlin.math.pow + +class Note(val id: Int) { + val noteName = NoteName.VALUES[id % NoteName.VALUES.size] + val octave = id / NoteName.VALUES.size - 1 + val frequency = noteName.baseFrequency * 2.0.pow(id / NoteName.VALUES.size - 5) + + operator fun plus(other: Int): Note { + if (other < 0 || other > 127) { + throw IllegalArgumentException("cannot add $other to note with id $id") + } + return NOTES[id + other] + } + + operator fun minus(other: Int): Note { + return this + (-other) + } + + companion object { + val NOTES = Array(128) { Note(it) } + + fun of(noteName: NoteName, octave: Int): Note { + return NOTES[NoteName.VALUES.size * (octave + 1) + noteName.index] + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/note/NoteName.kt b/app/src/main/java/com/lukas/music/song/note/NoteName.kt new file mode 100644 index 0000000..49c19b2 --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/note/NoteName.kt @@ -0,0 +1,32 @@ +package com.lukas.music.song.note + +import kotlin.math.pow + +const val A4 = 440.0 + +enum class NoteName(val index: Int, val asString: String) { + C(0, "C"), + Csharp(1, "C#"), + D(2, "D"), + Dsharp(3, "D#"), + E(4, "E"), + F(5, "F"), + Fsharp(6, "F#"), + G(7, "G"), + Gsharp(8, "G#"), + A(9, "A"), + Asharp(10, "A#"), + B(11, "B"), + ; + + val baseFrequency: Double = A4 * 2.0.pow(index.toDouble() / 12) + + operator fun plus(interval: Int): NoteName { + val resultPosition = (index + interval) % VALUES.size + return VALUES[resultPosition] + } + + companion object { + val VALUES = values() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt b/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt new file mode 100644 index 0000000..8714423 --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt @@ -0,0 +1,3 @@ +package com.lukas.music.song.voice + +class BassVoice \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/voice/Voice.kt b/app/src/main/java/com/lukas/music/song/voice/Voice.kt new file mode 100644 index 0000000..df4c83c --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/voice/Voice.kt @@ -0,0 +1,3 @@ +package com.lukas.music.song.voice + +class Voice \ No newline at end of file