diff --git a/.idea/misc.xml b/.idea/misc.xml
index 5c9d3cd..c668cf4 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -12,7 +12,7 @@
-
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 5c9d3cd..c668cf4 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 d40829a..ed56f52 100644
--- a/app/src/main/java/com/lukas/music/song/Song.kt
+++ b/app/src/main/java/com/lukas/music/song/Song.kt
@@ -3,22 +3,19 @@
import android.os.Handler
import android.os.Looper
import android.view.View
-import android.widget.TextView
-import androidx.core.view.doOnDetach
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.chords.Phrase
import com.lukas.music.song.note.Note
class Song(
var root: Note,
- val chordProgression: ChordProgression,
val beats: Int
) {
+ val chordProgression = ChordProgression(this)
private var beat = beats - 1
private lateinit var chord: Chord
- lateinit var chordDisplay: TextView
- private val beatCallback = mutableListOf<(Int, Int) -> Unit>()
fun step() {
if (chordProgression.phrases.isEmpty()) {
@@ -29,7 +26,14 @@
beat++
if (beat >= beats) {
beat = 0
+ var oldChord: Chord? = null
+ if (this::chord.isInitialized) {
+ oldChord = chord
+ }
chord = chordProgression.step()
+ for (callback in chordCallback) {
+ callback(oldChord ?: chord, chord)
+ }
}
for (callback in beatCallback) {
callback(before, beat)
@@ -39,22 +43,29 @@
for (voice in Instrument.voice) {
voice.step(root, chordNotes)
}
- chordDisplay.text = chord.toString(true, root)
}
}
companion object {
var currentSong = Song(
Note.NOTES[69],
- ChordProgression(),
4
)
+ private val beatCallback = mutableListOf<(Int, Int) -> Unit>()
+ private val chordCallback = mutableListOf<(Chord, Chord) -> Unit>()
+ val phraseCallback = mutableListOf<(Phrase) -> Unit>()
+
fun View.setOnBeatCallback(callback: (Int, Int) -> Unit) {
- currentSong.beatCallback += callback
- doOnDetach {
- currentSong.beatCallback.remove(callback)
- }
+ beatCallback += callback
+ }
+
+ fun View.setOnPhraseCallback(callback: (Phrase) -> Unit) {
+ phraseCallback += callback
+ }
+
+ fun View.setOnChordCallback(callback: (Chord, Chord) -> Unit) {
+ chordCallback += callback
}
}
}
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 5c9d3cd..c668cf4 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 d40829a..ed56f52 100644
--- a/app/src/main/java/com/lukas/music/song/Song.kt
+++ b/app/src/main/java/com/lukas/music/song/Song.kt
@@ -3,22 +3,19 @@
import android.os.Handler
import android.os.Looper
import android.view.View
-import android.widget.TextView
-import androidx.core.view.doOnDetach
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.chords.Phrase
import com.lukas.music.song.note.Note
class Song(
var root: Note,
- val chordProgression: ChordProgression,
val beats: Int
) {
+ val chordProgression = ChordProgression(this)
private var beat = beats - 1
private lateinit var chord: Chord
- lateinit var chordDisplay: TextView
- private val beatCallback = mutableListOf<(Int, Int) -> Unit>()
fun step() {
if (chordProgression.phrases.isEmpty()) {
@@ -29,7 +26,14 @@
beat++
if (beat >= beats) {
beat = 0
+ var oldChord: Chord? = null
+ if (this::chord.isInitialized) {
+ oldChord = chord
+ }
chord = chordProgression.step()
+ for (callback in chordCallback) {
+ callback(oldChord ?: chord, chord)
+ }
}
for (callback in beatCallback) {
callback(before, beat)
@@ -39,22 +43,29 @@
for (voice in Instrument.voice) {
voice.step(root, chordNotes)
}
- chordDisplay.text = chord.toString(true, root)
}
}
companion object {
var currentSong = Song(
Note.NOTES[69],
- ChordProgression(),
4
)
+ private val beatCallback = mutableListOf<(Int, Int) -> Unit>()
+ private val chordCallback = mutableListOf<(Chord, Chord) -> Unit>()
+ val phraseCallback = mutableListOf<(Phrase) -> Unit>()
+
fun View.setOnBeatCallback(callback: (Int, Int) -> Unit) {
- currentSong.beatCallback += callback
- doOnDetach {
- currentSong.beatCallback.remove(callback)
- }
+ beatCallback += callback
+ }
+
+ fun View.setOnPhraseCallback(callback: (Phrase) -> Unit) {
+ phraseCallback += callback
+ }
+
+ fun View.setOnChordCallback(callback: (Chord, Chord) -> Unit) {
+ chordCallback += callback
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/lukas/music/song/chords/ChordProgression.kt b/app/src/main/java/com/lukas/music/song/chords/ChordProgression.kt
index ba9419e..56e42ec 100644
--- a/app/src/main/java/com/lukas/music/song/chords/ChordProgression.kt
+++ b/app/src/main/java/com/lukas/music/song/chords/ChordProgression.kt
@@ -1,6 +1,8 @@
package com.lukas.music.song.chords
-class ChordProgression {
+import com.lukas.music.song.Song
+
+class ChordProgression(val song: Song) {
// TODO: special handler for increasing or decreasing measuresPerPhrase
val measuresPerPhrase: Int = 4
val phrases = mutableListOf()
@@ -14,6 +16,9 @@
operator fun inc(): ChordProgression {
position++
position %= phrases.size
+ for (callback in Song.phraseCallback) {
+ callback(phrases[position])
+ }
return this
}
}
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 5c9d3cd..c668cf4 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 d40829a..ed56f52 100644
--- a/app/src/main/java/com/lukas/music/song/Song.kt
+++ b/app/src/main/java/com/lukas/music/song/Song.kt
@@ -3,22 +3,19 @@
import android.os.Handler
import android.os.Looper
import android.view.View
-import android.widget.TextView
-import androidx.core.view.doOnDetach
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.chords.Phrase
import com.lukas.music.song.note.Note
class Song(
var root: Note,
- val chordProgression: ChordProgression,
val beats: Int
) {
+ val chordProgression = ChordProgression(this)
private var beat = beats - 1
private lateinit var chord: Chord
- lateinit var chordDisplay: TextView
- private val beatCallback = mutableListOf<(Int, Int) -> Unit>()
fun step() {
if (chordProgression.phrases.isEmpty()) {
@@ -29,7 +26,14 @@
beat++
if (beat >= beats) {
beat = 0
+ var oldChord: Chord? = null
+ if (this::chord.isInitialized) {
+ oldChord = chord
+ }
chord = chordProgression.step()
+ for (callback in chordCallback) {
+ callback(oldChord ?: chord, chord)
+ }
}
for (callback in beatCallback) {
callback(before, beat)
@@ -39,22 +43,29 @@
for (voice in Instrument.voice) {
voice.step(root, chordNotes)
}
- chordDisplay.text = chord.toString(true, root)
}
}
companion object {
var currentSong = Song(
Note.NOTES[69],
- ChordProgression(),
4
)
+ private val beatCallback = mutableListOf<(Int, Int) -> Unit>()
+ private val chordCallback = mutableListOf<(Chord, Chord) -> Unit>()
+ val phraseCallback = mutableListOf<(Phrase) -> Unit>()
+
fun View.setOnBeatCallback(callback: (Int, Int) -> Unit) {
- currentSong.beatCallback += callback
- doOnDetach {
- currentSong.beatCallback.remove(callback)
- }
+ beatCallback += callback
+ }
+
+ fun View.setOnPhraseCallback(callback: (Phrase) -> Unit) {
+ phraseCallback += callback
+ }
+
+ fun View.setOnChordCallback(callback: (Chord, Chord) -> Unit) {
+ chordCallback += callback
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/lukas/music/song/chords/ChordProgression.kt b/app/src/main/java/com/lukas/music/song/chords/ChordProgression.kt
index ba9419e..56e42ec 100644
--- a/app/src/main/java/com/lukas/music/song/chords/ChordProgression.kt
+++ b/app/src/main/java/com/lukas/music/song/chords/ChordProgression.kt
@@ -1,6 +1,8 @@
package com.lukas.music.song.chords
-class ChordProgression {
+import com.lukas.music.song.Song
+
+class ChordProgression(val song: Song) {
// TODO: special handler for increasing or decreasing measuresPerPhrase
val measuresPerPhrase: Int = 4
val phrases = mutableListOf()
@@ -14,6 +16,9 @@
operator fun inc(): ChordProgression {
position++
position %= phrases.size
+ for (callback in Song.phraseCallback) {
+ callback(phrases[position])
+ }
return this
}
}
\ No newline at end of file
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 48f9bcc..c8744cd 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
@@ -4,19 +4,23 @@
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.widget.RadioButton
-import android.widget.RadioGroup
-import android.widget.SeekBar
-import android.widget.Space
+import android.widget.*
+import androidx.cardview.widget.CardView
+import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
+import com.lukas.music.R
import com.lukas.music.databinding.FragmentPlayBinding
import com.lukas.music.instruments.Rhythm
import com.lukas.music.song.Song
import com.lukas.music.song.Song.Companion.setOnBeatCallback
+import com.lukas.music.song.Song.Companion.setOnChordCallback
+import com.lukas.music.song.Song.Companion.setOnPhraseCallback
+import com.lukas.music.song.chords.Chord
class PlayFragment : Fragment() {
lateinit var binding: FragmentPlayBinding
- val beatIndicators = mutableListOf()
+ private val beatIndicators = mutableListOf()
+ private val chordDisplays = mutableMapOf()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
@@ -66,11 +70,38 @@
beatIndicators += child
binding.beatIndicator.addView(child)
}
- Song.currentSong.chordDisplay = binding.currentChord
binding.root.setOnBeatCallback { before, now ->
beatIndicators[before].isChecked = false
beatIndicators[now].isChecked = true
}
+ binding.root.setOnPhraseCallback {
+ binding.phraseDisplay.removeAllViews()
+ chordDisplays.clear()
+ for (chord in it.chords) {
+ val card = CardView(binding.root.context)
+ val text = TextView(binding.root.context)
+ text.text = chord.toString(true, Song.currentSong.root)
+ card.layoutParams = SongFragment.layout
+ card.addView(text)
+ binding.phraseDisplay.addView(card)
+ chordDisplays[chord] = card
+ }
+ binding.phraseTable.isStretchAllColumns = true
+ }
+ binding.root.setOnChordCallback { old, new ->
+ chordDisplays[old]?.setBackgroundColor(
+ ContextCompat.getColor(
+ binding.root.context,
+ R.color.gray_600
+ )
+ )
+ chordDisplays[new]?.setBackgroundColor(
+ ContextCompat.getColor(
+ binding.root.context,
+ R.color.gray_400
+ )
+ )
+ }
return binding.root
}
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 5c9d3cd..c668cf4 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 d40829a..ed56f52 100644
--- a/app/src/main/java/com/lukas/music/song/Song.kt
+++ b/app/src/main/java/com/lukas/music/song/Song.kt
@@ -3,22 +3,19 @@
import android.os.Handler
import android.os.Looper
import android.view.View
-import android.widget.TextView
-import androidx.core.view.doOnDetach
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.chords.Phrase
import com.lukas.music.song.note.Note
class Song(
var root: Note,
- val chordProgression: ChordProgression,
val beats: Int
) {
+ val chordProgression = ChordProgression(this)
private var beat = beats - 1
private lateinit var chord: Chord
- lateinit var chordDisplay: TextView
- private val beatCallback = mutableListOf<(Int, Int) -> Unit>()
fun step() {
if (chordProgression.phrases.isEmpty()) {
@@ -29,7 +26,14 @@
beat++
if (beat >= beats) {
beat = 0
+ var oldChord: Chord? = null
+ if (this::chord.isInitialized) {
+ oldChord = chord
+ }
chord = chordProgression.step()
+ for (callback in chordCallback) {
+ callback(oldChord ?: chord, chord)
+ }
}
for (callback in beatCallback) {
callback(before, beat)
@@ -39,22 +43,29 @@
for (voice in Instrument.voice) {
voice.step(root, chordNotes)
}
- chordDisplay.text = chord.toString(true, root)
}
}
companion object {
var currentSong = Song(
Note.NOTES[69],
- ChordProgression(),
4
)
+ private val beatCallback = mutableListOf<(Int, Int) -> Unit>()
+ private val chordCallback = mutableListOf<(Chord, Chord) -> Unit>()
+ val phraseCallback = mutableListOf<(Phrase) -> Unit>()
+
fun View.setOnBeatCallback(callback: (Int, Int) -> Unit) {
- currentSong.beatCallback += callback
- doOnDetach {
- currentSong.beatCallback.remove(callback)
- }
+ beatCallback += callback
+ }
+
+ fun View.setOnPhraseCallback(callback: (Phrase) -> Unit) {
+ phraseCallback += callback
+ }
+
+ fun View.setOnChordCallback(callback: (Chord, Chord) -> Unit) {
+ chordCallback += callback
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/lukas/music/song/chords/ChordProgression.kt b/app/src/main/java/com/lukas/music/song/chords/ChordProgression.kt
index ba9419e..56e42ec 100644
--- a/app/src/main/java/com/lukas/music/song/chords/ChordProgression.kt
+++ b/app/src/main/java/com/lukas/music/song/chords/ChordProgression.kt
@@ -1,6 +1,8 @@
package com.lukas.music.song.chords
-class ChordProgression {
+import com.lukas.music.song.Song
+
+class ChordProgression(val song: Song) {
// TODO: special handler for increasing or decreasing measuresPerPhrase
val measuresPerPhrase: Int = 4
val phrases = mutableListOf()
@@ -14,6 +16,9 @@
operator fun inc(): ChordProgression {
position++
position %= phrases.size
+ for (callback in Song.phraseCallback) {
+ callback(phrases[position])
+ }
return this
}
}
\ No newline at end of file
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 48f9bcc..c8744cd 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
@@ -4,19 +4,23 @@
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.widget.RadioButton
-import android.widget.RadioGroup
-import android.widget.SeekBar
-import android.widget.Space
+import android.widget.*
+import androidx.cardview.widget.CardView
+import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
+import com.lukas.music.R
import com.lukas.music.databinding.FragmentPlayBinding
import com.lukas.music.instruments.Rhythm
import com.lukas.music.song.Song
import com.lukas.music.song.Song.Companion.setOnBeatCallback
+import com.lukas.music.song.Song.Companion.setOnChordCallback
+import com.lukas.music.song.Song.Companion.setOnPhraseCallback
+import com.lukas.music.song.chords.Chord
class PlayFragment : Fragment() {
lateinit var binding: FragmentPlayBinding
- val beatIndicators = mutableListOf()
+ private val beatIndicators = mutableListOf()
+ private val chordDisplays = mutableMapOf()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
@@ -66,11 +70,38 @@
beatIndicators += child
binding.beatIndicator.addView(child)
}
- Song.currentSong.chordDisplay = binding.currentChord
binding.root.setOnBeatCallback { before, now ->
beatIndicators[before].isChecked = false
beatIndicators[now].isChecked = true
}
+ binding.root.setOnPhraseCallback {
+ binding.phraseDisplay.removeAllViews()
+ chordDisplays.clear()
+ for (chord in it.chords) {
+ val card = CardView(binding.root.context)
+ val text = TextView(binding.root.context)
+ text.text = chord.toString(true, Song.currentSong.root)
+ card.layoutParams = SongFragment.layout
+ card.addView(text)
+ binding.phraseDisplay.addView(card)
+ chordDisplays[chord] = card
+ }
+ binding.phraseTable.isStretchAllColumns = true
+ }
+ binding.root.setOnChordCallback { old, new ->
+ chordDisplays[old]?.setBackgroundColor(
+ ContextCompat.getColor(
+ binding.root.context,
+ R.color.gray_600
+ )
+ )
+ chordDisplays[new]?.setBackgroundColor(
+ ContextCompat.getColor(
+ binding.root.context,
+ R.color.gray_400
+ )
+ )
+ }
return binding.root
}
diff --git a/app/src/main/res/layout/fragment_play.xml b/app/src/main/res/layout/fragment_play.xml
index 136de13..ace467f 100644
--- a/app/src/main/res/layout/fragment_play.xml
+++ b/app/src/main/res/layout/fragment_play.xml
@@ -58,15 +58,21 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/masterVolumeSlider" />
-
+ app:layout_constraintTop_toBottomOf="@+id/beatIndicator">
+
+
+
+
\ No newline at end of file