diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h index e3573c5..396a00f 100644 --- a/app/src/main/cpp/Envelope.h +++ b/app/src/main/cpp/Envelope.h @@ -18,7 +18,7 @@ float attackIncrement, delayIncrement, releaseIncrement; float value = 1; public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.1; + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.05; void initialize(AudioHost *host); void startNote(); diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h index e3573c5..396a00f 100644 --- a/app/src/main/cpp/Envelope.h +++ b/app/src/main/cpp/Envelope.h @@ -18,7 +18,7 @@ float attackIncrement, delayIncrement, releaseIncrement; float value = 1; public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.1; + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.05; void initialize(AudioHost *host); void startNote(); 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 811d16c..75307c3 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -2,6 +2,9 @@ import com.lukas.music.databinding.FragmentInstrumentBinding import com.lukas.music.song.note.Note +import com.lukas.music.song.voice.BassVoice +import com.lukas.music.song.voice.ChordVoice +import com.lukas.music.song.voice.Voice abstract class Instrument(private var name: String) { private var active = false @@ -19,12 +22,19 @@ } abstract fun startNote(note: Note) + abstract fun stop() abstract fun changeActive(newActive: Boolean) companion object { val instruments = mutableListOf( MonoInstrument("Bass"), + PolyInstrument("Chords"), ) + + val voice = mutableListOf( + BassVoice(instruments[0]), + ChordVoice(instruments[1]), + ) } } \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h index e3573c5..396a00f 100644 --- a/app/src/main/cpp/Envelope.h +++ b/app/src/main/cpp/Envelope.h @@ -18,7 +18,7 @@ float attackIncrement, delayIncrement, releaseIncrement; float value = 1; public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.1; + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.05; void initialize(AudioHost *host); void startNote(); 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 811d16c..75307c3 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -2,6 +2,9 @@ import com.lukas.music.databinding.FragmentInstrumentBinding import com.lukas.music.song.note.Note +import com.lukas.music.song.voice.BassVoice +import com.lukas.music.song.voice.ChordVoice +import com.lukas.music.song.voice.Voice abstract class Instrument(private var name: String) { private var active = false @@ -19,12 +22,19 @@ } abstract fun startNote(note: Note) + abstract fun stop() abstract fun changeActive(newActive: Boolean) companion object { val instruments = mutableListOf( MonoInstrument("Bass"), + PolyInstrument("Chords"), ) + + val voice = mutableListOf( + BassVoice(instruments[0]), + ChordVoice(instruments[1]), + ) } } \ No newline at end of file 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 1b53d5d..c3c8acc 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -12,4 +12,8 @@ override fun changeActive(newActive: Boolean) { internalInstrument.active = newActive } + + override fun stop() { + internalInstrument.endNote() + } } \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h index e3573c5..396a00f 100644 --- a/app/src/main/cpp/Envelope.h +++ b/app/src/main/cpp/Envelope.h @@ -18,7 +18,7 @@ float attackIncrement, delayIncrement, releaseIncrement; float value = 1; public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.1; + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.05; void initialize(AudioHost *host); void startNote(); 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 811d16c..75307c3 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -2,6 +2,9 @@ import com.lukas.music.databinding.FragmentInstrumentBinding import com.lukas.music.song.note.Note +import com.lukas.music.song.voice.BassVoice +import com.lukas.music.song.voice.ChordVoice +import com.lukas.music.song.voice.Voice abstract class Instrument(private var name: String) { private var active = false @@ -19,12 +22,19 @@ } abstract fun startNote(note: Note) + abstract fun stop() abstract fun changeActive(newActive: Boolean) companion object { val instruments = mutableListOf( MonoInstrument("Bass"), + PolyInstrument("Chords"), ) + + val voice = mutableListOf( + BassVoice(instruments[0]), + ChordVoice(instruments[1]), + ) } } \ No newline at end of file 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 1b53d5d..c3c8acc 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -12,4 +12,8 @@ override fun changeActive(newActive: Boolean) { internalInstrument.active = newActive } + + override fun stop() { + internalInstrument.endNote() + } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt b/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt index 54e6f3e..923c1f6 100644 --- a/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt @@ -1,3 +1,32 @@ package com.lukas.music.instruments -class PolyInstrument \ No newline at end of file +import com.lukas.music.song.note.Note + +class PolyInstrument(name: String) : Instrument(name) { + private val internalInstruments = Array(3) { InternalInstrument() } + private val playing = Array(3) { false } + + override fun startNote(note: Note) { + for ((index, instrumentPlaying) in playing.withIndex()) { + if (!instrumentPlaying) { + internalInstruments[index].startNote(note.frequency) + playing[index] = true + return + } + } + throw IllegalStateException("cannot start another note with the current amount of oscillators") + } + + override fun changeActive(newActive: Boolean) { + for (instrument in internalInstruments) { + instrument.active = newActive + } + } + + override fun stop() { + for ((i, instrument) in internalInstruments.withIndex()) { + instrument.endNote() + playing[i] = false + } + } +} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h index e3573c5..396a00f 100644 --- a/app/src/main/cpp/Envelope.h +++ b/app/src/main/cpp/Envelope.h @@ -18,7 +18,7 @@ float attackIncrement, delayIncrement, releaseIncrement; float value = 1; public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.1; + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.05; void initialize(AudioHost *host); void startNote(); 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 811d16c..75307c3 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -2,6 +2,9 @@ import com.lukas.music.databinding.FragmentInstrumentBinding import com.lukas.music.song.note.Note +import com.lukas.music.song.voice.BassVoice +import com.lukas.music.song.voice.ChordVoice +import com.lukas.music.song.voice.Voice abstract class Instrument(private var name: String) { private var active = false @@ -19,12 +22,19 @@ } abstract fun startNote(note: Note) + abstract fun stop() abstract fun changeActive(newActive: Boolean) companion object { val instruments = mutableListOf( MonoInstrument("Bass"), + PolyInstrument("Chords"), ) + + val voice = mutableListOf( + BassVoice(instruments[0]), + ChordVoice(instruments[1]), + ) } } \ No newline at end of file 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 1b53d5d..c3c8acc 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -12,4 +12,8 @@ override fun changeActive(newActive: Boolean) { internalInstrument.active = newActive } + + override fun stop() { + internalInstrument.endNote() + } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt b/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt index 54e6f3e..923c1f6 100644 --- a/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt @@ -1,3 +1,32 @@ package com.lukas.music.instruments -class PolyInstrument \ No newline at end of file +import com.lukas.music.song.note.Note + +class PolyInstrument(name: String) : Instrument(name) { + private val internalInstruments = Array(3) { InternalInstrument() } + private val playing = Array(3) { false } + + override fun startNote(note: Note) { + for ((index, instrumentPlaying) in playing.withIndex()) { + if (!instrumentPlaying) { + internalInstruments[index].startNote(note.frequency) + playing[index] = true + return + } + } + throw IllegalStateException("cannot start another note with the current amount of oscillators") + } + + override fun changeActive(newActive: Boolean) { + for (instrument in internalInstruments) { + instrument.active = newActive + } + } + + override fun stop() { + for ((i, instrument) in internalInstruments.withIndex()) { + instrument.endNote() + playing[i] = false + } + } +} \ No newline at end of file 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 c3328f1..807ce6c 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,9 @@ package com.lukas.music.song -class Chord(val note: Int, val chordType: ChordType) \ No newline at end of file +import com.lukas.music.song.note.Note + +class Chord(val note: Int, val chordType: ChordType) { + fun getNotes(root: Note): Array { + return Array(chordType.notes.size) { root + note + chordType.notes[it] } + } +} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h index e3573c5..396a00f 100644 --- a/app/src/main/cpp/Envelope.h +++ b/app/src/main/cpp/Envelope.h @@ -18,7 +18,7 @@ float attackIncrement, delayIncrement, releaseIncrement; float value = 1; public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.1; + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.05; void initialize(AudioHost *host); void startNote(); 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 811d16c..75307c3 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -2,6 +2,9 @@ import com.lukas.music.databinding.FragmentInstrumentBinding import com.lukas.music.song.note.Note +import com.lukas.music.song.voice.BassVoice +import com.lukas.music.song.voice.ChordVoice +import com.lukas.music.song.voice.Voice abstract class Instrument(private var name: String) { private var active = false @@ -19,12 +22,19 @@ } abstract fun startNote(note: Note) + abstract fun stop() abstract fun changeActive(newActive: Boolean) companion object { val instruments = mutableListOf( MonoInstrument("Bass"), + PolyInstrument("Chords"), ) + + val voice = mutableListOf( + BassVoice(instruments[0]), + ChordVoice(instruments[1]), + ) } } \ No newline at end of file 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 1b53d5d..c3c8acc 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -12,4 +12,8 @@ override fun changeActive(newActive: Boolean) { internalInstrument.active = newActive } + + override fun stop() { + internalInstrument.endNote() + } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt b/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt index 54e6f3e..923c1f6 100644 --- a/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt @@ -1,3 +1,32 @@ package com.lukas.music.instruments -class PolyInstrument \ No newline at end of file +import com.lukas.music.song.note.Note + +class PolyInstrument(name: String) : Instrument(name) { + private val internalInstruments = Array(3) { InternalInstrument() } + private val playing = Array(3) { false } + + override fun startNote(note: Note) { + for ((index, instrumentPlaying) in playing.withIndex()) { + if (!instrumentPlaying) { + internalInstruments[index].startNote(note.frequency) + playing[index] = true + return + } + } + throw IllegalStateException("cannot start another note with the current amount of oscillators") + } + + override fun changeActive(newActive: Boolean) { + for (instrument in internalInstruments) { + instrument.active = newActive + } + } + + override fun stop() { + for ((i, instrument) in internalInstruments.withIndex()) { + instrument.endNote() + playing[i] = false + } + } +} \ No newline at end of file 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 c3328f1..807ce6c 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,9 @@ package com.lukas.music.song -class Chord(val note: Int, val chordType: ChordType) \ No newline at end of file +import com.lukas.music.song.note.Note + +class Chord(val note: Int, val chordType: ChordType) { + fun getNotes(root: Note): Array { + return Array(chordType.notes.size) { root + note + chordType.notes[it] } + } +} \ 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 index a68adb6..5cab319 100644 --- a/app/src/main/java/com/lukas/music/song/ChordType.kt +++ b/app/src/main/java/com/lukas/music/song/ChordType.kt @@ -1,6 +1,6 @@ package com.lukas.music.song -enum class ChordType(private val notes: Array) { +enum class ChordType(val notes: Array) { Major(arrayOf(0, 4, 7)), Minor(arrayOf(0, 3, 7)), ; diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h index e3573c5..396a00f 100644 --- a/app/src/main/cpp/Envelope.h +++ b/app/src/main/cpp/Envelope.h @@ -18,7 +18,7 @@ float attackIncrement, delayIncrement, releaseIncrement; float value = 1; public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.1; + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.05; void initialize(AudioHost *host); void startNote(); 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 811d16c..75307c3 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -2,6 +2,9 @@ import com.lukas.music.databinding.FragmentInstrumentBinding import com.lukas.music.song.note.Note +import com.lukas.music.song.voice.BassVoice +import com.lukas.music.song.voice.ChordVoice +import com.lukas.music.song.voice.Voice abstract class Instrument(private var name: String) { private var active = false @@ -19,12 +22,19 @@ } abstract fun startNote(note: Note) + abstract fun stop() abstract fun changeActive(newActive: Boolean) companion object { val instruments = mutableListOf( MonoInstrument("Bass"), + PolyInstrument("Chords"), ) + + val voice = mutableListOf( + BassVoice(instruments[0]), + ChordVoice(instruments[1]), + ) } } \ No newline at end of file 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 1b53d5d..c3c8acc 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -12,4 +12,8 @@ override fun changeActive(newActive: Boolean) { internalInstrument.active = newActive } + + override fun stop() { + internalInstrument.endNote() + } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt b/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt index 54e6f3e..923c1f6 100644 --- a/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt @@ -1,3 +1,32 @@ package com.lukas.music.instruments -class PolyInstrument \ No newline at end of file +import com.lukas.music.song.note.Note + +class PolyInstrument(name: String) : Instrument(name) { + private val internalInstruments = Array(3) { InternalInstrument() } + private val playing = Array(3) { false } + + override fun startNote(note: Note) { + for ((index, instrumentPlaying) in playing.withIndex()) { + if (!instrumentPlaying) { + internalInstruments[index].startNote(note.frequency) + playing[index] = true + return + } + } + throw IllegalStateException("cannot start another note with the current amount of oscillators") + } + + override fun changeActive(newActive: Boolean) { + for (instrument in internalInstruments) { + instrument.active = newActive + } + } + + override fun stop() { + for ((i, instrument) in internalInstruments.withIndex()) { + instrument.endNote() + playing[i] = false + } + } +} \ No newline at end of file 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 c3328f1..807ce6c 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,9 @@ package com.lukas.music.song -class Chord(val note: Int, val chordType: ChordType) \ No newline at end of file +import com.lukas.music.song.note.Note + +class Chord(val note: Int, val chordType: ChordType) { + fun getNotes(root: Note): Array { + return Array(chordType.notes.size) { root + note + chordType.notes[it] } + } +} \ 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 index a68adb6..5cab319 100644 --- a/app/src/main/java/com/lukas/music/song/ChordType.kt +++ b/app/src/main/java/com/lukas/music/song/ChordType.kt @@ -1,6 +1,6 @@ package com.lukas.music.song -enum class ChordType(private val notes: Array) { +enum class ChordType(val notes: Array) { Major(arrayOf(0, 4, 7)), Minor(arrayOf(0, 3, 7)), ; 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 9f9dd78..09879f0 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -8,10 +8,20 @@ private val root: Note, private val chordProgression: ChordProgression, ) { + private var beat = 0 + private var chord: Chord = chordProgression.step() + fun step() { - val chord = chordProgression.step() - for (instrument in Instrument.instruments) { - instrument.startNote(root + chord.note) + val chordNotes = chord.getNotes(root) + for (voice in Instrument.voice) { + if (beat in voice.steps) { + voice.step(root, chordNotes) + } + } + beat++ + if (beat > 4) { + beat -= 4 + chord = chordProgression.step() } } @@ -20,10 +30,10 @@ Note.of(NoteName.F, 4), ChordProgression( listOf( - Chord(1, ChordType.Major), - Chord(6, ChordType.Major), + Chord(0, ChordType.Major), + Chord(5, ChordType.Major), Chord(2, ChordType.Minor), - Chord(8, ChordType.Major), + Chord(7, ChordType.Major), ) ) ) diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h index e3573c5..396a00f 100644 --- a/app/src/main/cpp/Envelope.h +++ b/app/src/main/cpp/Envelope.h @@ -18,7 +18,7 @@ float attackIncrement, delayIncrement, releaseIncrement; float value = 1; public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.1; + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.05; void initialize(AudioHost *host); void startNote(); 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 811d16c..75307c3 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -2,6 +2,9 @@ import com.lukas.music.databinding.FragmentInstrumentBinding import com.lukas.music.song.note.Note +import com.lukas.music.song.voice.BassVoice +import com.lukas.music.song.voice.ChordVoice +import com.lukas.music.song.voice.Voice abstract class Instrument(private var name: String) { private var active = false @@ -19,12 +22,19 @@ } abstract fun startNote(note: Note) + abstract fun stop() abstract fun changeActive(newActive: Boolean) companion object { val instruments = mutableListOf( MonoInstrument("Bass"), + PolyInstrument("Chords"), ) + + val voice = mutableListOf( + BassVoice(instruments[0]), + ChordVoice(instruments[1]), + ) } } \ No newline at end of file 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 1b53d5d..c3c8acc 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -12,4 +12,8 @@ override fun changeActive(newActive: Boolean) { internalInstrument.active = newActive } + + override fun stop() { + internalInstrument.endNote() + } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt b/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt index 54e6f3e..923c1f6 100644 --- a/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt @@ -1,3 +1,32 @@ package com.lukas.music.instruments -class PolyInstrument \ No newline at end of file +import com.lukas.music.song.note.Note + +class PolyInstrument(name: String) : Instrument(name) { + private val internalInstruments = Array(3) { InternalInstrument() } + private val playing = Array(3) { false } + + override fun startNote(note: Note) { + for ((index, instrumentPlaying) in playing.withIndex()) { + if (!instrumentPlaying) { + internalInstruments[index].startNote(note.frequency) + playing[index] = true + return + } + } + throw IllegalStateException("cannot start another note with the current amount of oscillators") + } + + override fun changeActive(newActive: Boolean) { + for (instrument in internalInstruments) { + instrument.active = newActive + } + } + + override fun stop() { + for ((i, instrument) in internalInstruments.withIndex()) { + instrument.endNote() + playing[i] = false + } + } +} \ No newline at end of file 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 c3328f1..807ce6c 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,9 @@ package com.lukas.music.song -class Chord(val note: Int, val chordType: ChordType) \ No newline at end of file +import com.lukas.music.song.note.Note + +class Chord(val note: Int, val chordType: ChordType) { + fun getNotes(root: Note): Array { + return Array(chordType.notes.size) { root + note + chordType.notes[it] } + } +} \ 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 index a68adb6..5cab319 100644 --- a/app/src/main/java/com/lukas/music/song/ChordType.kt +++ b/app/src/main/java/com/lukas/music/song/ChordType.kt @@ -1,6 +1,6 @@ package com.lukas.music.song -enum class ChordType(private val notes: Array) { +enum class ChordType(val notes: Array) { Major(arrayOf(0, 4, 7)), Minor(arrayOf(0, 3, 7)), ; 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 9f9dd78..09879f0 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -8,10 +8,20 @@ private val root: Note, private val chordProgression: ChordProgression, ) { + private var beat = 0 + private var chord: Chord = chordProgression.step() + fun step() { - val chord = chordProgression.step() - for (instrument in Instrument.instruments) { - instrument.startNote(root + chord.note) + val chordNotes = chord.getNotes(root) + for (voice in Instrument.voice) { + if (beat in voice.steps) { + voice.step(root, chordNotes) + } + } + beat++ + if (beat > 4) { + beat -= 4 + chord = chordProgression.step() } } @@ -20,10 +30,10 @@ Note.of(NoteName.F, 4), ChordProgression( listOf( - Chord(1, ChordType.Major), - Chord(6, ChordType.Major), + Chord(0, ChordType.Major), + Chord(5, ChordType.Major), Chord(2, ChordType.Minor), - Chord(8, ChordType.Major), + Chord(7, ChordType.Major), ) ) ) 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 index 0005d13..b2111a7 100644 --- a/app/src/main/java/com/lukas/music/song/note/Note.kt +++ b/app/src/main/java/com/lukas/music/song/note/Note.kt @@ -3,12 +3,12 @@ import kotlin.math.pow class Note(val id: Int) { - val noteName = NoteName.VALUES[id % NoteName.VALUES.size] + private 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) { + if (id + other < 0 || id + other > 127) { throw IllegalArgumentException("cannot add $other to note with id $id") } return NOTES[id + other] diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h index e3573c5..396a00f 100644 --- a/app/src/main/cpp/Envelope.h +++ b/app/src/main/cpp/Envelope.h @@ -18,7 +18,7 @@ float attackIncrement, delayIncrement, releaseIncrement; float value = 1; public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.1; + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.05; void initialize(AudioHost *host); void startNote(); 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 811d16c..75307c3 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -2,6 +2,9 @@ import com.lukas.music.databinding.FragmentInstrumentBinding import com.lukas.music.song.note.Note +import com.lukas.music.song.voice.BassVoice +import com.lukas.music.song.voice.ChordVoice +import com.lukas.music.song.voice.Voice abstract class Instrument(private var name: String) { private var active = false @@ -19,12 +22,19 @@ } abstract fun startNote(note: Note) + abstract fun stop() abstract fun changeActive(newActive: Boolean) companion object { val instruments = mutableListOf( MonoInstrument("Bass"), + PolyInstrument("Chords"), ) + + val voice = mutableListOf( + BassVoice(instruments[0]), + ChordVoice(instruments[1]), + ) } } \ No newline at end of file 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 1b53d5d..c3c8acc 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -12,4 +12,8 @@ override fun changeActive(newActive: Boolean) { internalInstrument.active = newActive } + + override fun stop() { + internalInstrument.endNote() + } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt b/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt index 54e6f3e..923c1f6 100644 --- a/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt @@ -1,3 +1,32 @@ package com.lukas.music.instruments -class PolyInstrument \ No newline at end of file +import com.lukas.music.song.note.Note + +class PolyInstrument(name: String) : Instrument(name) { + private val internalInstruments = Array(3) { InternalInstrument() } + private val playing = Array(3) { false } + + override fun startNote(note: Note) { + for ((index, instrumentPlaying) in playing.withIndex()) { + if (!instrumentPlaying) { + internalInstruments[index].startNote(note.frequency) + playing[index] = true + return + } + } + throw IllegalStateException("cannot start another note with the current amount of oscillators") + } + + override fun changeActive(newActive: Boolean) { + for (instrument in internalInstruments) { + instrument.active = newActive + } + } + + override fun stop() { + for ((i, instrument) in internalInstruments.withIndex()) { + instrument.endNote() + playing[i] = false + } + } +} \ No newline at end of file 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 c3328f1..807ce6c 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,9 @@ package com.lukas.music.song -class Chord(val note: Int, val chordType: ChordType) \ No newline at end of file +import com.lukas.music.song.note.Note + +class Chord(val note: Int, val chordType: ChordType) { + fun getNotes(root: Note): Array { + return Array(chordType.notes.size) { root + note + chordType.notes[it] } + } +} \ 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 index a68adb6..5cab319 100644 --- a/app/src/main/java/com/lukas/music/song/ChordType.kt +++ b/app/src/main/java/com/lukas/music/song/ChordType.kt @@ -1,6 +1,6 @@ package com.lukas.music.song -enum class ChordType(private val notes: Array) { +enum class ChordType(val notes: Array) { Major(arrayOf(0, 4, 7)), Minor(arrayOf(0, 3, 7)), ; 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 9f9dd78..09879f0 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -8,10 +8,20 @@ private val root: Note, private val chordProgression: ChordProgression, ) { + private var beat = 0 + private var chord: Chord = chordProgression.step() + fun step() { - val chord = chordProgression.step() - for (instrument in Instrument.instruments) { - instrument.startNote(root + chord.note) + val chordNotes = chord.getNotes(root) + for (voice in Instrument.voice) { + if (beat in voice.steps) { + voice.step(root, chordNotes) + } + } + beat++ + if (beat > 4) { + beat -= 4 + chord = chordProgression.step() } } @@ -20,10 +30,10 @@ Note.of(NoteName.F, 4), ChordProgression( listOf( - Chord(1, ChordType.Major), - Chord(6, ChordType.Major), + Chord(0, ChordType.Major), + Chord(5, ChordType.Major), Chord(2, ChordType.Minor), - Chord(8, ChordType.Major), + Chord(7, ChordType.Major), ) ) ) 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 index 0005d13..b2111a7 100644 --- a/app/src/main/java/com/lukas/music/song/note/Note.kt +++ b/app/src/main/java/com/lukas/music/song/note/Note.kt @@ -3,12 +3,12 @@ import kotlin.math.pow class Note(val id: Int) { - val noteName = NoteName.VALUES[id % NoteName.VALUES.size] + private 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) { + if (id + other < 0 || id + other > 127) { throw IllegalArgumentException("cannot add $other to note with id $id") } return NOTES[id + other] 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 index 49c19b2..5b58671 100644 --- a/app/src/main/java/com/lukas/music/song/note/NoteName.kt +++ b/app/src/main/java/com/lukas/music/song/note/NoteName.kt @@ -2,7 +2,7 @@ import kotlin.math.pow -const val A4 = 440.0 +const val A4 = 261.63 enum class NoteName(val index: Int, val asString: String) { C(0, "C"), diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h index e3573c5..396a00f 100644 --- a/app/src/main/cpp/Envelope.h +++ b/app/src/main/cpp/Envelope.h @@ -18,7 +18,7 @@ float attackIncrement, delayIncrement, releaseIncrement; float value = 1; public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.1; + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.05; void initialize(AudioHost *host); void startNote(); 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 811d16c..75307c3 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -2,6 +2,9 @@ import com.lukas.music.databinding.FragmentInstrumentBinding import com.lukas.music.song.note.Note +import com.lukas.music.song.voice.BassVoice +import com.lukas.music.song.voice.ChordVoice +import com.lukas.music.song.voice.Voice abstract class Instrument(private var name: String) { private var active = false @@ -19,12 +22,19 @@ } abstract fun startNote(note: Note) + abstract fun stop() abstract fun changeActive(newActive: Boolean) companion object { val instruments = mutableListOf( MonoInstrument("Bass"), + PolyInstrument("Chords"), ) + + val voice = mutableListOf( + BassVoice(instruments[0]), + ChordVoice(instruments[1]), + ) } } \ No newline at end of file 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 1b53d5d..c3c8acc 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -12,4 +12,8 @@ override fun changeActive(newActive: Boolean) { internalInstrument.active = newActive } + + override fun stop() { + internalInstrument.endNote() + } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt b/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt index 54e6f3e..923c1f6 100644 --- a/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt @@ -1,3 +1,32 @@ package com.lukas.music.instruments -class PolyInstrument \ No newline at end of file +import com.lukas.music.song.note.Note + +class PolyInstrument(name: String) : Instrument(name) { + private val internalInstruments = Array(3) { InternalInstrument() } + private val playing = Array(3) { false } + + override fun startNote(note: Note) { + for ((index, instrumentPlaying) in playing.withIndex()) { + if (!instrumentPlaying) { + internalInstruments[index].startNote(note.frequency) + playing[index] = true + return + } + } + throw IllegalStateException("cannot start another note with the current amount of oscillators") + } + + override fun changeActive(newActive: Boolean) { + for (instrument in internalInstruments) { + instrument.active = newActive + } + } + + override fun stop() { + for ((i, instrument) in internalInstruments.withIndex()) { + instrument.endNote() + playing[i] = false + } + } +} \ No newline at end of file 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 c3328f1..807ce6c 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,9 @@ package com.lukas.music.song -class Chord(val note: Int, val chordType: ChordType) \ No newline at end of file +import com.lukas.music.song.note.Note + +class Chord(val note: Int, val chordType: ChordType) { + fun getNotes(root: Note): Array { + return Array(chordType.notes.size) { root + note + chordType.notes[it] } + } +} \ 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 index a68adb6..5cab319 100644 --- a/app/src/main/java/com/lukas/music/song/ChordType.kt +++ b/app/src/main/java/com/lukas/music/song/ChordType.kt @@ -1,6 +1,6 @@ package com.lukas.music.song -enum class ChordType(private val notes: Array) { +enum class ChordType(val notes: Array) { Major(arrayOf(0, 4, 7)), Minor(arrayOf(0, 3, 7)), ; 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 9f9dd78..09879f0 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -8,10 +8,20 @@ private val root: Note, private val chordProgression: ChordProgression, ) { + private var beat = 0 + private var chord: Chord = chordProgression.step() + fun step() { - val chord = chordProgression.step() - for (instrument in Instrument.instruments) { - instrument.startNote(root + chord.note) + val chordNotes = chord.getNotes(root) + for (voice in Instrument.voice) { + if (beat in voice.steps) { + voice.step(root, chordNotes) + } + } + beat++ + if (beat > 4) { + beat -= 4 + chord = chordProgression.step() } } @@ -20,10 +30,10 @@ Note.of(NoteName.F, 4), ChordProgression( listOf( - Chord(1, ChordType.Major), - Chord(6, ChordType.Major), + Chord(0, ChordType.Major), + Chord(5, ChordType.Major), Chord(2, ChordType.Minor), - Chord(8, ChordType.Major), + Chord(7, ChordType.Major), ) ) ) 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 index 0005d13..b2111a7 100644 --- a/app/src/main/java/com/lukas/music/song/note/Note.kt +++ b/app/src/main/java/com/lukas/music/song/note/Note.kt @@ -3,12 +3,12 @@ import kotlin.math.pow class Note(val id: Int) { - val noteName = NoteName.VALUES[id % NoteName.VALUES.size] + private 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) { + if (id + other < 0 || id + other > 127) { throw IllegalArgumentException("cannot add $other to note with id $id") } return NOTES[id + other] 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 index 49c19b2..5b58671 100644 --- a/app/src/main/java/com/lukas/music/song/note/NoteName.kt +++ b/app/src/main/java/com/lukas/music/song/note/NoteName.kt @@ -2,7 +2,7 @@ import kotlin.math.pow -const val A4 = 440.0 +const val A4 = 261.63 enum class NoteName(val index: Int, val asString: String) { C(0, "C"), 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 index 8714423..ae7e16b 100644 --- a/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt +++ b/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt @@ -1,3 +1,13 @@ package com.lukas.music.song.voice -class BassVoice \ No newline at end of file +import com.lukas.music.instruments.Instrument +import com.lukas.music.song.note.Note +import com.lukas.music.song.note.NoteName + +class BassVoice(instrument: Instrument) : Voice(instrument) { + override val steps = listOf(1, 3) + + override fun step(root: Note, chord: Array) { + instrument.startNote(chord[0] - NoteName.VALUES.size * 2) + } +} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h index e3573c5..396a00f 100644 --- a/app/src/main/cpp/Envelope.h +++ b/app/src/main/cpp/Envelope.h @@ -18,7 +18,7 @@ float attackIncrement, delayIncrement, releaseIncrement; float value = 1; public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.1; + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.05; void initialize(AudioHost *host); void startNote(); 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 811d16c..75307c3 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -2,6 +2,9 @@ import com.lukas.music.databinding.FragmentInstrumentBinding import com.lukas.music.song.note.Note +import com.lukas.music.song.voice.BassVoice +import com.lukas.music.song.voice.ChordVoice +import com.lukas.music.song.voice.Voice abstract class Instrument(private var name: String) { private var active = false @@ -19,12 +22,19 @@ } abstract fun startNote(note: Note) + abstract fun stop() abstract fun changeActive(newActive: Boolean) companion object { val instruments = mutableListOf( MonoInstrument("Bass"), + PolyInstrument("Chords"), ) + + val voice = mutableListOf( + BassVoice(instruments[0]), + ChordVoice(instruments[1]), + ) } } \ No newline at end of file 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 1b53d5d..c3c8acc 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -12,4 +12,8 @@ override fun changeActive(newActive: Boolean) { internalInstrument.active = newActive } + + override fun stop() { + internalInstrument.endNote() + } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt b/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt index 54e6f3e..923c1f6 100644 --- a/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt @@ -1,3 +1,32 @@ package com.lukas.music.instruments -class PolyInstrument \ No newline at end of file +import com.lukas.music.song.note.Note + +class PolyInstrument(name: String) : Instrument(name) { + private val internalInstruments = Array(3) { InternalInstrument() } + private val playing = Array(3) { false } + + override fun startNote(note: Note) { + for ((index, instrumentPlaying) in playing.withIndex()) { + if (!instrumentPlaying) { + internalInstruments[index].startNote(note.frequency) + playing[index] = true + return + } + } + throw IllegalStateException("cannot start another note with the current amount of oscillators") + } + + override fun changeActive(newActive: Boolean) { + for (instrument in internalInstruments) { + instrument.active = newActive + } + } + + override fun stop() { + for ((i, instrument) in internalInstruments.withIndex()) { + instrument.endNote() + playing[i] = false + } + } +} \ No newline at end of file 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 c3328f1..807ce6c 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,9 @@ package com.lukas.music.song -class Chord(val note: Int, val chordType: ChordType) \ No newline at end of file +import com.lukas.music.song.note.Note + +class Chord(val note: Int, val chordType: ChordType) { + fun getNotes(root: Note): Array { + return Array(chordType.notes.size) { root + note + chordType.notes[it] } + } +} \ 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 index a68adb6..5cab319 100644 --- a/app/src/main/java/com/lukas/music/song/ChordType.kt +++ b/app/src/main/java/com/lukas/music/song/ChordType.kt @@ -1,6 +1,6 @@ package com.lukas.music.song -enum class ChordType(private val notes: Array) { +enum class ChordType(val notes: Array) { Major(arrayOf(0, 4, 7)), Minor(arrayOf(0, 3, 7)), ; 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 9f9dd78..09879f0 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -8,10 +8,20 @@ private val root: Note, private val chordProgression: ChordProgression, ) { + private var beat = 0 + private var chord: Chord = chordProgression.step() + fun step() { - val chord = chordProgression.step() - for (instrument in Instrument.instruments) { - instrument.startNote(root + chord.note) + val chordNotes = chord.getNotes(root) + for (voice in Instrument.voice) { + if (beat in voice.steps) { + voice.step(root, chordNotes) + } + } + beat++ + if (beat > 4) { + beat -= 4 + chord = chordProgression.step() } } @@ -20,10 +30,10 @@ Note.of(NoteName.F, 4), ChordProgression( listOf( - Chord(1, ChordType.Major), - Chord(6, ChordType.Major), + Chord(0, ChordType.Major), + Chord(5, ChordType.Major), Chord(2, ChordType.Minor), - Chord(8, ChordType.Major), + Chord(7, ChordType.Major), ) ) ) 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 index 0005d13..b2111a7 100644 --- a/app/src/main/java/com/lukas/music/song/note/Note.kt +++ b/app/src/main/java/com/lukas/music/song/note/Note.kt @@ -3,12 +3,12 @@ import kotlin.math.pow class Note(val id: Int) { - val noteName = NoteName.VALUES[id % NoteName.VALUES.size] + private 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) { + if (id + other < 0 || id + other > 127) { throw IllegalArgumentException("cannot add $other to note with id $id") } return NOTES[id + other] 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 index 49c19b2..5b58671 100644 --- a/app/src/main/java/com/lukas/music/song/note/NoteName.kt +++ b/app/src/main/java/com/lukas/music/song/note/NoteName.kt @@ -2,7 +2,7 @@ import kotlin.math.pow -const val A4 = 440.0 +const val A4 = 261.63 enum class NoteName(val index: Int, val asString: String) { C(0, "C"), 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 index 8714423..ae7e16b 100644 --- a/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt +++ b/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt @@ -1,3 +1,13 @@ package com.lukas.music.song.voice -class BassVoice \ No newline at end of file +import com.lukas.music.instruments.Instrument +import com.lukas.music.song.note.Note +import com.lukas.music.song.note.NoteName + +class BassVoice(instrument: Instrument) : Voice(instrument) { + override val steps = listOf(1, 3) + + override fun step(root: Note, chord: Array) { + instrument.startNote(chord[0] - NoteName.VALUES.size * 2) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/voice/ChordVoice.kt b/app/src/main/java/com/lukas/music/song/voice/ChordVoice.kt new file mode 100644 index 0000000..d173023 --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/voice/ChordVoice.kt @@ -0,0 +1,15 @@ +package com.lukas.music.song.voice + +import com.lukas.music.instruments.Instrument +import com.lukas.music.song.note.Note + +class ChordVoice(instrument: Instrument) : Voice(instrument) { + override val steps: List = listOf(2, 4) + + override fun step(root: Note, chord: Array) { + instrument.stop() + for (note in chord) { + instrument.startNote(note) + } + } +} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h index e3573c5..396a00f 100644 --- a/app/src/main/cpp/Envelope.h +++ b/app/src/main/cpp/Envelope.h @@ -18,7 +18,7 @@ float attackIncrement, delayIncrement, releaseIncrement; float value = 1; public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.1; + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 0.05; void initialize(AudioHost *host); void startNote(); 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 811d16c..75307c3 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -2,6 +2,9 @@ import com.lukas.music.databinding.FragmentInstrumentBinding import com.lukas.music.song.note.Note +import com.lukas.music.song.voice.BassVoice +import com.lukas.music.song.voice.ChordVoice +import com.lukas.music.song.voice.Voice abstract class Instrument(private var name: String) { private var active = false @@ -19,12 +22,19 @@ } abstract fun startNote(note: Note) + abstract fun stop() abstract fun changeActive(newActive: Boolean) companion object { val instruments = mutableListOf( MonoInstrument("Bass"), + PolyInstrument("Chords"), ) + + val voice = mutableListOf( + BassVoice(instruments[0]), + ChordVoice(instruments[1]), + ) } } \ No newline at end of file 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 1b53d5d..c3c8acc 100644 --- a/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/MonoInstrument.kt @@ -12,4 +12,8 @@ override fun changeActive(newActive: Boolean) { internalInstrument.active = newActive } + + override fun stop() { + internalInstrument.endNote() + } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt b/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt index 54e6f3e..923c1f6 100644 --- a/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/PolyInstrument.kt @@ -1,3 +1,32 @@ package com.lukas.music.instruments -class PolyInstrument \ No newline at end of file +import com.lukas.music.song.note.Note + +class PolyInstrument(name: String) : Instrument(name) { + private val internalInstruments = Array(3) { InternalInstrument() } + private val playing = Array(3) { false } + + override fun startNote(note: Note) { + for ((index, instrumentPlaying) in playing.withIndex()) { + if (!instrumentPlaying) { + internalInstruments[index].startNote(note.frequency) + playing[index] = true + return + } + } + throw IllegalStateException("cannot start another note with the current amount of oscillators") + } + + override fun changeActive(newActive: Boolean) { + for (instrument in internalInstruments) { + instrument.active = newActive + } + } + + override fun stop() { + for ((i, instrument) in internalInstruments.withIndex()) { + instrument.endNote() + playing[i] = false + } + } +} \ No newline at end of file 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 c3328f1..807ce6c 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,9 @@ package com.lukas.music.song -class Chord(val note: Int, val chordType: ChordType) \ No newline at end of file +import com.lukas.music.song.note.Note + +class Chord(val note: Int, val chordType: ChordType) { + fun getNotes(root: Note): Array { + return Array(chordType.notes.size) { root + note + chordType.notes[it] } + } +} \ 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 index a68adb6..5cab319 100644 --- a/app/src/main/java/com/lukas/music/song/ChordType.kt +++ b/app/src/main/java/com/lukas/music/song/ChordType.kt @@ -1,6 +1,6 @@ package com.lukas.music.song -enum class ChordType(private val notes: Array) { +enum class ChordType(val notes: Array) { Major(arrayOf(0, 4, 7)), Minor(arrayOf(0, 3, 7)), ; 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 9f9dd78..09879f0 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -8,10 +8,20 @@ private val root: Note, private val chordProgression: ChordProgression, ) { + private var beat = 0 + private var chord: Chord = chordProgression.step() + fun step() { - val chord = chordProgression.step() - for (instrument in Instrument.instruments) { - instrument.startNote(root + chord.note) + val chordNotes = chord.getNotes(root) + for (voice in Instrument.voice) { + if (beat in voice.steps) { + voice.step(root, chordNotes) + } + } + beat++ + if (beat > 4) { + beat -= 4 + chord = chordProgression.step() } } @@ -20,10 +30,10 @@ Note.of(NoteName.F, 4), ChordProgression( listOf( - Chord(1, ChordType.Major), - Chord(6, ChordType.Major), + Chord(0, ChordType.Major), + Chord(5, ChordType.Major), Chord(2, ChordType.Minor), - Chord(8, ChordType.Major), + Chord(7, ChordType.Major), ) ) ) 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 index 0005d13..b2111a7 100644 --- a/app/src/main/java/com/lukas/music/song/note/Note.kt +++ b/app/src/main/java/com/lukas/music/song/note/Note.kt @@ -3,12 +3,12 @@ import kotlin.math.pow class Note(val id: Int) { - val noteName = NoteName.VALUES[id % NoteName.VALUES.size] + private 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) { + if (id + other < 0 || id + other > 127) { throw IllegalArgumentException("cannot add $other to note with id $id") } return NOTES[id + other] 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 index 49c19b2..5b58671 100644 --- a/app/src/main/java/com/lukas/music/song/note/NoteName.kt +++ b/app/src/main/java/com/lukas/music/song/note/NoteName.kt @@ -2,7 +2,7 @@ import kotlin.math.pow -const val A4 = 440.0 +const val A4 = 261.63 enum class NoteName(val index: Int, val asString: String) { C(0, "C"), 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 index 8714423..ae7e16b 100644 --- a/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt +++ b/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt @@ -1,3 +1,13 @@ package com.lukas.music.song.voice -class BassVoice \ No newline at end of file +import com.lukas.music.instruments.Instrument +import com.lukas.music.song.note.Note +import com.lukas.music.song.note.NoteName + +class BassVoice(instrument: Instrument) : Voice(instrument) { + override val steps = listOf(1, 3) + + override fun step(root: Note, chord: Array) { + instrument.startNote(chord[0] - NoteName.VALUES.size * 2) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/voice/ChordVoice.kt b/app/src/main/java/com/lukas/music/song/voice/ChordVoice.kt new file mode 100644 index 0000000..d173023 --- /dev/null +++ b/app/src/main/java/com/lukas/music/song/voice/ChordVoice.kt @@ -0,0 +1,15 @@ +package com.lukas.music.song.voice + +import com.lukas.music.instruments.Instrument +import com.lukas.music.song.note.Note + +class ChordVoice(instrument: Instrument) : Voice(instrument) { + override val steps: List = listOf(2, 4) + + override fun step(root: Note, chord: Array) { + instrument.stop() + for (note in chord) { + instrument.startNote(note) + } + } +} \ 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 index df4c83c..8347c73 100644 --- a/app/src/main/java/com/lukas/music/song/voice/Voice.kt +++ b/app/src/main/java/com/lukas/music/song/voice/Voice.kt @@ -1,3 +1,10 @@ package com.lukas.music.song.voice -class Voice \ No newline at end of file +import com.lukas.music.instruments.Instrument +import com.lukas.music.song.note.Note + +abstract class Voice(val instrument: Instrument) { + abstract val steps: List + + abstract fun step(root: Note, chord: Array) +} \ No newline at end of file