diff --git a/.idea/misc.xml b/.idea/misc.xml index e3b7c48..5c9d3cd 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -12,7 +12,7 @@ - + diff --git a/.idea/misc.xml b/.idea/misc.xml index e3b7c48..5c9d3cd 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -12,7 +12,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 f3d36ec..e666dca 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -1,7 +1,6 @@ package com.lukas.music.song import com.lukas.music.instruments.Instrument -import com.lukas.music.song.chords.Chord import com.lukas.music.song.chords.ChordProgression import com.lukas.music.song.note.Note import com.lukas.music.util.Cycle @@ -11,22 +10,19 @@ val beats: Int ) : Cycle(beats) { val chordProgression = ChordProgression() - private lateinit var chord: Chord init { for (i in 0 until beats) { this += i } wraparoundListeners += { - chordProgression.step()?.let { chord = it.currentItem } + chordProgression.step() } } override fun step(): Int { super.step() - if (!this::chord.isInitialized) { - return index - } + val chord = chordProgression.currentItem?.currentItem ?: return index val chordNotes = chord.getNotes(root) for (voice in Instrument.voice) { voice.step(root, chordNotes) diff --git a/.idea/misc.xml b/.idea/misc.xml index e3b7c48..5c9d3cd 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -12,7 +12,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 f3d36ec..e666dca 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -1,7 +1,6 @@ package com.lukas.music.song import com.lukas.music.instruments.Instrument -import com.lukas.music.song.chords.Chord import com.lukas.music.song.chords.ChordProgression import com.lukas.music.song.note.Note import com.lukas.music.util.Cycle @@ -11,22 +10,19 @@ val beats: Int ) : Cycle(beats) { val chordProgression = ChordProgression() - private lateinit var chord: Chord init { for (i in 0 until beats) { this += i } wraparoundListeners += { - chordProgression.step()?.let { chord = it.currentItem } + chordProgression.step() } } override fun step(): Int { super.step() - if (!this::chord.isInitialized) { - return index - } + val chord = chordProgression.currentItem?.currentItem ?: return index val chordNotes = chord.getNotes(root) for (voice in Instrument.voice) { voice.step(root, chordNotes) diff --git a/app/src/main/java/com/lukas/music/ui/fragments/PlayFragment.kt b/app/src/main/java/com/lukas/music/ui/fragments/PlayFragment.kt index 597c100..ba3d0b1 100644 --- a/app/src/main/java/com/lukas/music/ui/fragments/PlayFragment.kt +++ b/app/src/main/java/com/lukas/music/ui/fragments/PlayFragment.kt @@ -31,6 +31,23 @@ if (Rhythm.on) android.R.drawable.ic_media_pause else android.R.drawable.ic_media_play ) } + binding.advancePhraseButton.setOnClickListener { + Song.currentSong.chordProgression.bigStep(true) + } + binding.reversePhraseButton.setOnClickListener { + Song.currentSong.chordProgression.bigReverse(true) + } + binding.advanceMeasureButton.setOnClickListener { + Song.currentSong.chordProgression.step() + } + binding.reverseMeasureButton.setOnClickListener { + Song.currentSong.chordProgression.currentItem?.let { + chordDisplays[it.index].setCardBackgroundColor( + ContextCompat.getColor(binding.root.context, R.color.gray_0x40) + ) + } + Song.currentSong.chordProgression.reverse() + } setupSlider(binding.masterVolumeSlider, 0, 100, 100) { setMasterVolume(it.toDouble() / 100.0) binding.masterVolumeText.text = "Master volume: $it%" @@ -80,13 +97,10 @@ if (chordDisplays.isEmpty()) { putChords() } - chordDisplays[Song.currentSong.chordProgression.currentItem.index].setCardBackgroundColor( + chordDisplays[Song.currentSong.chordProgression.currentItem!!.index].setCardBackgroundColor( ContextCompat.getColor(binding.root.context, R.color.purple_700) ) - if (Song.currentSong.chordProgression.currentItem.index == 0) { - return - } - chordDisplays[Song.currentSong.chordProgression.currentItem.indexBehind].setCardBackgroundColor( + chordDisplays[Song.currentSong.chordProgression.currentItem!!.indexBehind].setCardBackgroundColor( ContextCompat.getColor(binding.root.context, R.color.gray_0x40) ) } @@ -121,7 +135,7 @@ private fun putChords() { binding.phraseDisplay.removeAllViews() chordDisplays.clear() - for (chord in Song.currentSong.chordProgression.currentItem) { + for (chord in Song.currentSong.chordProgression.currentItem ?: return) { val card = CardView(binding.root.context) card.layoutParams = SongFragment.tableRowLayout card.radius = 10f diff --git a/.idea/misc.xml b/.idea/misc.xml index e3b7c48..5c9d3cd 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -12,7 +12,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 f3d36ec..e666dca 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -1,7 +1,6 @@ package com.lukas.music.song import com.lukas.music.instruments.Instrument -import com.lukas.music.song.chords.Chord import com.lukas.music.song.chords.ChordProgression import com.lukas.music.song.note.Note import com.lukas.music.util.Cycle @@ -11,22 +10,19 @@ val beats: Int ) : Cycle(beats) { val chordProgression = ChordProgression() - private lateinit var chord: Chord init { for (i in 0 until beats) { this += i } wraparoundListeners += { - chordProgression.step()?.let { chord = it.currentItem } + chordProgression.step() } } override fun step(): Int { super.step() - if (!this::chord.isInitialized) { - return index - } + val chord = chordProgression.currentItem?.currentItem ?: return index val chordNotes = chord.getNotes(root) for (voice in Instrument.voice) { voice.step(root, chordNotes) diff --git a/app/src/main/java/com/lukas/music/ui/fragments/PlayFragment.kt b/app/src/main/java/com/lukas/music/ui/fragments/PlayFragment.kt index 597c100..ba3d0b1 100644 --- a/app/src/main/java/com/lukas/music/ui/fragments/PlayFragment.kt +++ b/app/src/main/java/com/lukas/music/ui/fragments/PlayFragment.kt @@ -31,6 +31,23 @@ if (Rhythm.on) android.R.drawable.ic_media_pause else android.R.drawable.ic_media_play ) } + binding.advancePhraseButton.setOnClickListener { + Song.currentSong.chordProgression.bigStep(true) + } + binding.reversePhraseButton.setOnClickListener { + Song.currentSong.chordProgression.bigReverse(true) + } + binding.advanceMeasureButton.setOnClickListener { + Song.currentSong.chordProgression.step() + } + binding.reverseMeasureButton.setOnClickListener { + Song.currentSong.chordProgression.currentItem?.let { + chordDisplays[it.index].setCardBackgroundColor( + ContextCompat.getColor(binding.root.context, R.color.gray_0x40) + ) + } + Song.currentSong.chordProgression.reverse() + } setupSlider(binding.masterVolumeSlider, 0, 100, 100) { setMasterVolume(it.toDouble() / 100.0) binding.masterVolumeText.text = "Master volume: $it%" @@ -80,13 +97,10 @@ if (chordDisplays.isEmpty()) { putChords() } - chordDisplays[Song.currentSong.chordProgression.currentItem.index].setCardBackgroundColor( + chordDisplays[Song.currentSong.chordProgression.currentItem!!.index].setCardBackgroundColor( ContextCompat.getColor(binding.root.context, R.color.purple_700) ) - if (Song.currentSong.chordProgression.currentItem.index == 0) { - return - } - chordDisplays[Song.currentSong.chordProgression.currentItem.indexBehind].setCardBackgroundColor( + chordDisplays[Song.currentSong.chordProgression.currentItem!!.indexBehind].setCardBackgroundColor( ContextCompat.getColor(binding.root.context, R.color.gray_0x40) ) } @@ -121,7 +135,7 @@ private fun putChords() { binding.phraseDisplay.removeAllViews() chordDisplays.clear() - for (chord in Song.currentSong.chordProgression.currentItem) { + for (chord in Song.currentSong.chordProgression.currentItem ?: return) { val card = CardView(binding.root.context) card.layoutParams = SongFragment.tableRowLayout card.radius = 10f diff --git a/app/src/main/java/com/lukas/music/util/Cycle.kt b/app/src/main/java/com/lukas/music/util/Cycle.kt index 4bf3ec5..7e49239 100644 --- a/app/src/main/java/com/lukas/music/util/Cycle.kt +++ b/app/src/main/java/com/lukas/music/util/Cycle.kt @@ -8,8 +8,8 @@ val indexBehind: Int get() = (index - 1 + size) % size - val currentItem: T - get() = this[index] + val currentItem: T? + get() = if (size == 0) null else this[index] open fun step(): T? { if (size == 0) { @@ -28,6 +28,22 @@ return this[index] } + open fun reset() { + index = size - 1 + step() + } + + open fun reverse() { + if (size == 0) { + return + } + index = indexBehind + // TODO: back around handlers + for (callback in stepCallback) { + callback() + } + } + fun lookahead(distance: Int): T { return this[(index + distance) % size] } @@ -53,4 +69,52 @@ } return this[index] } + + override fun reset() { + this[index].reset() + super.reset() + } + + fun bigStep(keepSubindex: Boolean = false) { + val subindex = currentItem?.index ?: return + currentItem?.index = currentItem!!.size - 1 + step() + if (keepSubindex) { + currentItem?.index = subindex + currentItem?.index = currentItem?.indexBehind ?: return + currentItem?.step() + for (callback in miniStepCallback) { + callback() + } + } + } + + override fun reverse() { + currentItem?.reverse() ?: return + if (currentItem!!.index == currentItem!!.size - 1) { + currentItem!!.reset() + super.reverse() + currentItem!!.index = currentItem!!.size - 1 + } + for (callback in miniStepCallback) { + callback() + } + } + + fun bigReverse(keepSubindex: Boolean = false) { + val subindex = currentItem?.index ?: return + currentItem?.reset() + index = indexBehind + index = indexBehind + currentItem?.index = currentItem!!.size - 1 + step() + if (keepSubindex) { + currentItem?.index = subindex + currentItem?.index = currentItem!!.indexBehind + currentItem?.step() + for (callback in miniStepCallback) { + callback() + } + } + } } \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index e3b7c48..5c9d3cd 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -12,7 +12,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 f3d36ec..e666dca 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -1,7 +1,6 @@ package com.lukas.music.song import com.lukas.music.instruments.Instrument -import com.lukas.music.song.chords.Chord import com.lukas.music.song.chords.ChordProgression import com.lukas.music.song.note.Note import com.lukas.music.util.Cycle @@ -11,22 +10,19 @@ val beats: Int ) : Cycle(beats) { val chordProgression = ChordProgression() - private lateinit var chord: Chord init { for (i in 0 until beats) { this += i } wraparoundListeners += { - chordProgression.step()?.let { chord = it.currentItem } + chordProgression.step() } } override fun step(): Int { super.step() - if (!this::chord.isInitialized) { - return index - } + val chord = chordProgression.currentItem?.currentItem ?: return index val chordNotes = chord.getNotes(root) for (voice in Instrument.voice) { voice.step(root, chordNotes) diff --git a/app/src/main/java/com/lukas/music/ui/fragments/PlayFragment.kt b/app/src/main/java/com/lukas/music/ui/fragments/PlayFragment.kt index 597c100..ba3d0b1 100644 --- a/app/src/main/java/com/lukas/music/ui/fragments/PlayFragment.kt +++ b/app/src/main/java/com/lukas/music/ui/fragments/PlayFragment.kt @@ -31,6 +31,23 @@ if (Rhythm.on) android.R.drawable.ic_media_pause else android.R.drawable.ic_media_play ) } + binding.advancePhraseButton.setOnClickListener { + Song.currentSong.chordProgression.bigStep(true) + } + binding.reversePhraseButton.setOnClickListener { + Song.currentSong.chordProgression.bigReverse(true) + } + binding.advanceMeasureButton.setOnClickListener { + Song.currentSong.chordProgression.step() + } + binding.reverseMeasureButton.setOnClickListener { + Song.currentSong.chordProgression.currentItem?.let { + chordDisplays[it.index].setCardBackgroundColor( + ContextCompat.getColor(binding.root.context, R.color.gray_0x40) + ) + } + Song.currentSong.chordProgression.reverse() + } setupSlider(binding.masterVolumeSlider, 0, 100, 100) { setMasterVolume(it.toDouble() / 100.0) binding.masterVolumeText.text = "Master volume: $it%" @@ -80,13 +97,10 @@ if (chordDisplays.isEmpty()) { putChords() } - chordDisplays[Song.currentSong.chordProgression.currentItem.index].setCardBackgroundColor( + chordDisplays[Song.currentSong.chordProgression.currentItem!!.index].setCardBackgroundColor( ContextCompat.getColor(binding.root.context, R.color.purple_700) ) - if (Song.currentSong.chordProgression.currentItem.index == 0) { - return - } - chordDisplays[Song.currentSong.chordProgression.currentItem.indexBehind].setCardBackgroundColor( + chordDisplays[Song.currentSong.chordProgression.currentItem!!.indexBehind].setCardBackgroundColor( ContextCompat.getColor(binding.root.context, R.color.gray_0x40) ) } @@ -121,7 +135,7 @@ private fun putChords() { binding.phraseDisplay.removeAllViews() chordDisplays.clear() - for (chord in Song.currentSong.chordProgression.currentItem) { + for (chord in Song.currentSong.chordProgression.currentItem ?: return) { val card = CardView(binding.root.context) card.layoutParams = SongFragment.tableRowLayout card.radius = 10f diff --git a/app/src/main/java/com/lukas/music/util/Cycle.kt b/app/src/main/java/com/lukas/music/util/Cycle.kt index 4bf3ec5..7e49239 100644 --- a/app/src/main/java/com/lukas/music/util/Cycle.kt +++ b/app/src/main/java/com/lukas/music/util/Cycle.kt @@ -8,8 +8,8 @@ val indexBehind: Int get() = (index - 1 + size) % size - val currentItem: T - get() = this[index] + val currentItem: T? + get() = if (size == 0) null else this[index] open fun step(): T? { if (size == 0) { @@ -28,6 +28,22 @@ return this[index] } + open fun reset() { + index = size - 1 + step() + } + + open fun reverse() { + if (size == 0) { + return + } + index = indexBehind + // TODO: back around handlers + for (callback in stepCallback) { + callback() + } + } + fun lookahead(distance: Int): T { return this[(index + distance) % size] } @@ -53,4 +69,52 @@ } return this[index] } + + override fun reset() { + this[index].reset() + super.reset() + } + + fun bigStep(keepSubindex: Boolean = false) { + val subindex = currentItem?.index ?: return + currentItem?.index = currentItem!!.size - 1 + step() + if (keepSubindex) { + currentItem?.index = subindex + currentItem?.index = currentItem?.indexBehind ?: return + currentItem?.step() + for (callback in miniStepCallback) { + callback() + } + } + } + + override fun reverse() { + currentItem?.reverse() ?: return + if (currentItem!!.index == currentItem!!.size - 1) { + currentItem!!.reset() + super.reverse() + currentItem!!.index = currentItem!!.size - 1 + } + for (callback in miniStepCallback) { + callback() + } + } + + fun bigReverse(keepSubindex: Boolean = false) { + val subindex = currentItem?.index ?: return + currentItem?.reset() + index = indexBehind + index = indexBehind + currentItem?.index = currentItem!!.size - 1 + step() + if (keepSubindex) { + currentItem?.index = subindex + currentItem?.index = currentItem!!.indexBehind + currentItem?.step() + for (callback in miniStepCallback) { + callback() + } + } + } } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_play.xml b/app/src/main/res/layout/fragment_play.xml index fe27cd5..e4182bf 100644 --- a/app/src/main/res/layout/fragment_play.xml +++ b/app/src/main/res/layout/fragment_play.xml @@ -33,6 +33,63 @@ tools:layout_conversion_absoluteHeight="56dp" tools:layout_conversion_absoluteWidth="56dp" /> + + + + + + + + diff --git a/.idea/misc.xml b/.idea/misc.xml index e3b7c48..5c9d3cd 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -12,7 +12,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 f3d36ec..e666dca 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -1,7 +1,6 @@ package com.lukas.music.song import com.lukas.music.instruments.Instrument -import com.lukas.music.song.chords.Chord import com.lukas.music.song.chords.ChordProgression import com.lukas.music.song.note.Note import com.lukas.music.util.Cycle @@ -11,22 +10,19 @@ val beats: Int ) : Cycle(beats) { val chordProgression = ChordProgression() - private lateinit var chord: Chord init { for (i in 0 until beats) { this += i } wraparoundListeners += { - chordProgression.step()?.let { chord = it.currentItem } + chordProgression.step() } } override fun step(): Int { super.step() - if (!this::chord.isInitialized) { - return index - } + val chord = chordProgression.currentItem?.currentItem ?: return index val chordNotes = chord.getNotes(root) for (voice in Instrument.voice) { voice.step(root, chordNotes) diff --git a/app/src/main/java/com/lukas/music/ui/fragments/PlayFragment.kt b/app/src/main/java/com/lukas/music/ui/fragments/PlayFragment.kt index 597c100..ba3d0b1 100644 --- a/app/src/main/java/com/lukas/music/ui/fragments/PlayFragment.kt +++ b/app/src/main/java/com/lukas/music/ui/fragments/PlayFragment.kt @@ -31,6 +31,23 @@ if (Rhythm.on) android.R.drawable.ic_media_pause else android.R.drawable.ic_media_play ) } + binding.advancePhraseButton.setOnClickListener { + Song.currentSong.chordProgression.bigStep(true) + } + binding.reversePhraseButton.setOnClickListener { + Song.currentSong.chordProgression.bigReverse(true) + } + binding.advanceMeasureButton.setOnClickListener { + Song.currentSong.chordProgression.step() + } + binding.reverseMeasureButton.setOnClickListener { + Song.currentSong.chordProgression.currentItem?.let { + chordDisplays[it.index].setCardBackgroundColor( + ContextCompat.getColor(binding.root.context, R.color.gray_0x40) + ) + } + Song.currentSong.chordProgression.reverse() + } setupSlider(binding.masterVolumeSlider, 0, 100, 100) { setMasterVolume(it.toDouble() / 100.0) binding.masterVolumeText.text = "Master volume: $it%" @@ -80,13 +97,10 @@ if (chordDisplays.isEmpty()) { putChords() } - chordDisplays[Song.currentSong.chordProgression.currentItem.index].setCardBackgroundColor( + chordDisplays[Song.currentSong.chordProgression.currentItem!!.index].setCardBackgroundColor( ContextCompat.getColor(binding.root.context, R.color.purple_700) ) - if (Song.currentSong.chordProgression.currentItem.index == 0) { - return - } - chordDisplays[Song.currentSong.chordProgression.currentItem.indexBehind].setCardBackgroundColor( + chordDisplays[Song.currentSong.chordProgression.currentItem!!.indexBehind].setCardBackgroundColor( ContextCompat.getColor(binding.root.context, R.color.gray_0x40) ) } @@ -121,7 +135,7 @@ private fun putChords() { binding.phraseDisplay.removeAllViews() chordDisplays.clear() - for (chord in Song.currentSong.chordProgression.currentItem) { + for (chord in Song.currentSong.chordProgression.currentItem ?: return) { val card = CardView(binding.root.context) card.layoutParams = SongFragment.tableRowLayout card.radius = 10f diff --git a/app/src/main/java/com/lukas/music/util/Cycle.kt b/app/src/main/java/com/lukas/music/util/Cycle.kt index 4bf3ec5..7e49239 100644 --- a/app/src/main/java/com/lukas/music/util/Cycle.kt +++ b/app/src/main/java/com/lukas/music/util/Cycle.kt @@ -8,8 +8,8 @@ val indexBehind: Int get() = (index - 1 + size) % size - val currentItem: T - get() = this[index] + val currentItem: T? + get() = if (size == 0) null else this[index] open fun step(): T? { if (size == 0) { @@ -28,6 +28,22 @@ return this[index] } + open fun reset() { + index = size - 1 + step() + } + + open fun reverse() { + if (size == 0) { + return + } + index = indexBehind + // TODO: back around handlers + for (callback in stepCallback) { + callback() + } + } + fun lookahead(distance: Int): T { return this[(index + distance) % size] } @@ -53,4 +69,52 @@ } return this[index] } + + override fun reset() { + this[index].reset() + super.reset() + } + + fun bigStep(keepSubindex: Boolean = false) { + val subindex = currentItem?.index ?: return + currentItem?.index = currentItem!!.size - 1 + step() + if (keepSubindex) { + currentItem?.index = subindex + currentItem?.index = currentItem?.indexBehind ?: return + currentItem?.step() + for (callback in miniStepCallback) { + callback() + } + } + } + + override fun reverse() { + currentItem?.reverse() ?: return + if (currentItem!!.index == currentItem!!.size - 1) { + currentItem!!.reset() + super.reverse() + currentItem!!.index = currentItem!!.size - 1 + } + for (callback in miniStepCallback) { + callback() + } + } + + fun bigReverse(keepSubindex: Boolean = false) { + val subindex = currentItem?.index ?: return + currentItem?.reset() + index = indexBehind + index = indexBehind + currentItem?.index = currentItem!!.size - 1 + step() + if (keepSubindex) { + currentItem?.index = subindex + currentItem?.index = currentItem!!.indexBehind + currentItem?.step() + for (callback in miniStepCallback) { + callback() + } + } + } } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_play.xml b/app/src/main/res/layout/fragment_play.xml index fe27cd5..e4182bf 100644 --- a/app/src/main/res/layout/fragment_play.xml +++ b/app/src/main/res/layout/fragment_play.xml @@ -33,6 +33,63 @@ tools:layout_conversion_absoluteHeight="56dp" tools:layout_conversion_absoluteWidth="56dp" /> + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1ba02a4..c125463 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -19,4 +19,9 @@ Chord pitch Chord type Exit this menu + Go to the next measure + Go to the start of the current measure + Go to the next phrase + Go to the start of the current phrase + Next chord not known yet . . . \ No newline at end of file