diff --git a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt b/app/src/main/java/com/lukas/music/EditVoiceFragment.kt deleted file mode 100644 index 56f21e6..0000000 --- a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2022 Lukas Eisenhauer - * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or(at your option) any later version. - * - * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If not, see . - */ - -package com.lukas.music - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TableRow -import androidx.core.view.setMargins -import androidx.fragment.app.DialogFragment -import com.google.android.material.button.MaterialButton -import com.lukas.music.databinding.FragmentEditVoiceBinding -import com.lukas.music.song.Song -import com.lukas.music.song.voice.Voice -import com.lukas.music.util.ArrayProperty -import com.lukas.music.util.setupToggle - -class EditVoiceFragment(private val voice: Voice) : DialogFragment() { - private lateinit var binding: FragmentEditVoiceBinding - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - binding = FragmentEditVoiceBinding.inflate(inflater) - for (row in 0 until voice.noteCount) { - val rowLayout = TableRow(binding.root.context) - for (column in 0 until Song.currentSong.beats) { - val button = MaterialButton(binding.root.context) - button.layoutParams = buttonLayout - button.setupToggle(ArrayProperty(voice.noteActive[column], row), R.color.blue) - rowLayout.addView(button) - } - binding.noteGrid.addView(rowLayout) - } - binding.noteGrid.isStretchAllColumns = true - binding.closeButton.setOnClickListener { - dismiss() - } - return binding.root - } - - override fun onStart() { - super.onStart() - dialog?.window?.setLayout( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - ) - } - - companion object { - val buttonLayout = TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT) - - init { - buttonLayout.setMargins(5) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt b/app/src/main/java/com/lukas/music/EditVoiceFragment.kt deleted file mode 100644 index 56f21e6..0000000 --- a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2022 Lukas Eisenhauer - * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or(at your option) any later version. - * - * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If not, see . - */ - -package com.lukas.music - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TableRow -import androidx.core.view.setMargins -import androidx.fragment.app.DialogFragment -import com.google.android.material.button.MaterialButton -import com.lukas.music.databinding.FragmentEditVoiceBinding -import com.lukas.music.song.Song -import com.lukas.music.song.voice.Voice -import com.lukas.music.util.ArrayProperty -import com.lukas.music.util.setupToggle - -class EditVoiceFragment(private val voice: Voice) : DialogFragment() { - private lateinit var binding: FragmentEditVoiceBinding - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - binding = FragmentEditVoiceBinding.inflate(inflater) - for (row in 0 until voice.noteCount) { - val rowLayout = TableRow(binding.root.context) - for (column in 0 until Song.currentSong.beats) { - val button = MaterialButton(binding.root.context) - button.layoutParams = buttonLayout - button.setupToggle(ArrayProperty(voice.noteActive[column], row), R.color.blue) - rowLayout.addView(button) - } - binding.noteGrid.addView(rowLayout) - } - binding.noteGrid.isStretchAllColumns = true - binding.closeButton.setOnClickListener { - dismiss() - } - return binding.root - } - - override fun onStart() { - super.onStart() - dialog?.window?.setLayout( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - ) - } - - companion object { - val buttonLayout = TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT) - - init { - buttonLayout.setMargins(5) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt index 75c1545..b310c72 100644 --- a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt +++ b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt @@ -36,6 +36,10 @@ if (this::task.isInitialized) { task.cancel() } - task = timer.schedule((60000 / tempo).toLong(), (60000 / tempo).toLong(), callback) + task = timer.schedule( + (60000 / tempo / Song.currentSong.subBeats).toLong(), + (60000 / tempo / Song.currentSong.subBeats).toLong(), + callback + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt b/app/src/main/java/com/lukas/music/EditVoiceFragment.kt deleted file mode 100644 index 56f21e6..0000000 --- a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2022 Lukas Eisenhauer - * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or(at your option) any later version. - * - * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If not, see . - */ - -package com.lukas.music - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TableRow -import androidx.core.view.setMargins -import androidx.fragment.app.DialogFragment -import com.google.android.material.button.MaterialButton -import com.lukas.music.databinding.FragmentEditVoiceBinding -import com.lukas.music.song.Song -import com.lukas.music.song.voice.Voice -import com.lukas.music.util.ArrayProperty -import com.lukas.music.util.setupToggle - -class EditVoiceFragment(private val voice: Voice) : DialogFragment() { - private lateinit var binding: FragmentEditVoiceBinding - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - binding = FragmentEditVoiceBinding.inflate(inflater) - for (row in 0 until voice.noteCount) { - val rowLayout = TableRow(binding.root.context) - for (column in 0 until Song.currentSong.beats) { - val button = MaterialButton(binding.root.context) - button.layoutParams = buttonLayout - button.setupToggle(ArrayProperty(voice.noteActive[column], row), R.color.blue) - rowLayout.addView(button) - } - binding.noteGrid.addView(rowLayout) - } - binding.noteGrid.isStretchAllColumns = true - binding.closeButton.setOnClickListener { - dismiss() - } - return binding.root - } - - override fun onStart() { - super.onStart() - dialog?.window?.setLayout( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - ) - } - - companion object { - val buttonLayout = TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT) - - init { - buttonLayout.setMargins(5) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt index 75c1545..b310c72 100644 --- a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt +++ b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt @@ -36,6 +36,10 @@ if (this::task.isInitialized) { task.cancel() } - task = timer.schedule((60000 / tempo).toLong(), (60000 / tempo).toLong(), callback) + task = timer.schedule( + (60000 / tempo / Song.currentSong.subBeats).toLong(), + (60000 / tempo / Song.currentSong.subBeats).toLong(), + callback + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Song.kt b/app/src/main/java/com/lukas/music/song/Song.kt index fc5421b..5046664 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -14,11 +14,13 @@ import com.lukas.music.song.chords.ChordProgression import com.lukas.music.song.note.Note import com.lukas.music.util.Cycle +import com.lukas.music.util.MetaCycle class Song( root: Note, - val beats: Int -) : Cycle(beats) { + val beats: Int, + val subBeats: Int, +) : MetaCycle>() { val chordProgression = ChordProgression() var soloInstrument: Instrument? = null set(value) { @@ -46,7 +48,11 @@ init { for (i in 0 until beats) { - this += i + val cycle = Cycle() + for (j in 0 until subBeats) { + cycle += j + } + this += cycle } wraparoundListeners += { chordProgression.step() @@ -54,24 +60,25 @@ } } - override fun step(): Int { + override fun step(): Cycle? { super.step() - val chord = chordProgression.currentItem?.currentItem ?: return index + val chord = chordProgression.currentItem?.currentItem ?: return currentItem val chordNotes = chord.getNotes(root) soloInstrument?.let { - it.voice.step(root, chordNotes, index) + it.voice.step(root, chordNotes, index, currentItem!!.index) } ?: run { for (instrument in Instrument.instruments) { - instrument.voice.step(root, chordNotes, index) + instrument.voice.step(root, chordNotes, index, currentItem!!.index) } } - return index + return currentItem } companion object { var currentSong = Song( Note.NOTES[69], - 4 + 4, + 2, ) } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt b/app/src/main/java/com/lukas/music/EditVoiceFragment.kt deleted file mode 100644 index 56f21e6..0000000 --- a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2022 Lukas Eisenhauer - * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or(at your option) any later version. - * - * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If not, see . - */ - -package com.lukas.music - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TableRow -import androidx.core.view.setMargins -import androidx.fragment.app.DialogFragment -import com.google.android.material.button.MaterialButton -import com.lukas.music.databinding.FragmentEditVoiceBinding -import com.lukas.music.song.Song -import com.lukas.music.song.voice.Voice -import com.lukas.music.util.ArrayProperty -import com.lukas.music.util.setupToggle - -class EditVoiceFragment(private val voice: Voice) : DialogFragment() { - private lateinit var binding: FragmentEditVoiceBinding - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - binding = FragmentEditVoiceBinding.inflate(inflater) - for (row in 0 until voice.noteCount) { - val rowLayout = TableRow(binding.root.context) - for (column in 0 until Song.currentSong.beats) { - val button = MaterialButton(binding.root.context) - button.layoutParams = buttonLayout - button.setupToggle(ArrayProperty(voice.noteActive[column], row), R.color.blue) - rowLayout.addView(button) - } - binding.noteGrid.addView(rowLayout) - } - binding.noteGrid.isStretchAllColumns = true - binding.closeButton.setOnClickListener { - dismiss() - } - return binding.root - } - - override fun onStart() { - super.onStart() - dialog?.window?.setLayout( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - ) - } - - companion object { - val buttonLayout = TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT) - - init { - buttonLayout.setMargins(5) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt index 75c1545..b310c72 100644 --- a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt +++ b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt @@ -36,6 +36,10 @@ if (this::task.isInitialized) { task.cancel() } - task = timer.schedule((60000 / tempo).toLong(), (60000 / tempo).toLong(), callback) + task = timer.schedule( + (60000 / tempo / Song.currentSong.subBeats).toLong(), + (60000 / tempo / Song.currentSong.subBeats).toLong(), + callback + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Song.kt b/app/src/main/java/com/lukas/music/song/Song.kt index fc5421b..5046664 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -14,11 +14,13 @@ import com.lukas.music.song.chords.ChordProgression import com.lukas.music.song.note.Note import com.lukas.music.util.Cycle +import com.lukas.music.util.MetaCycle class Song( root: Note, - val beats: Int -) : Cycle(beats) { + val beats: Int, + val subBeats: Int, +) : MetaCycle>() { val chordProgression = ChordProgression() var soloInstrument: Instrument? = null set(value) { @@ -46,7 +48,11 @@ init { for (i in 0 until beats) { - this += i + val cycle = Cycle() + for (j in 0 until subBeats) { + cycle += j + } + this += cycle } wraparoundListeners += { chordProgression.step() @@ -54,24 +60,25 @@ } } - override fun step(): Int { + override fun step(): Cycle? { super.step() - val chord = chordProgression.currentItem?.currentItem ?: return index + val chord = chordProgression.currentItem?.currentItem ?: return currentItem val chordNotes = chord.getNotes(root) soloInstrument?.let { - it.voice.step(root, chordNotes, index) + it.voice.step(root, chordNotes, index, currentItem!!.index) } ?: run { for (instrument in Instrument.instruments) { - instrument.voice.step(root, chordNotes, index) + instrument.voice.step(root, chordNotes, index, currentItem!!.index) } } - return index + return currentItem } companion object { var currentSong = Song( Note.NOTES[69], - 4 + 4, + 2, ) } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt b/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt index 4706068..66650a2 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 @@ -14,14 +14,7 @@ import com.lukas.music.song.note.Note class BassVoice(instrument: Instrument) : Voice(instrument) { - override var noteActive: Array> = arrayOf( - arrayOf(true), - arrayOf(false), - arrayOf(true), - arrayOf(false) - ) - - override val noteCount: Int = 1 + override val noteCount: Int get() = 1 override fun getNotes(root: Note, chordNotes: Array): Array { return arrayOf(chordNotes[0] - 24) diff --git a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt b/app/src/main/java/com/lukas/music/EditVoiceFragment.kt deleted file mode 100644 index 56f21e6..0000000 --- a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2022 Lukas Eisenhauer - * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or(at your option) any later version. - * - * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If not, see . - */ - -package com.lukas.music - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TableRow -import androidx.core.view.setMargins -import androidx.fragment.app.DialogFragment -import com.google.android.material.button.MaterialButton -import com.lukas.music.databinding.FragmentEditVoiceBinding -import com.lukas.music.song.Song -import com.lukas.music.song.voice.Voice -import com.lukas.music.util.ArrayProperty -import com.lukas.music.util.setupToggle - -class EditVoiceFragment(private val voice: Voice) : DialogFragment() { - private lateinit var binding: FragmentEditVoiceBinding - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - binding = FragmentEditVoiceBinding.inflate(inflater) - for (row in 0 until voice.noteCount) { - val rowLayout = TableRow(binding.root.context) - for (column in 0 until Song.currentSong.beats) { - val button = MaterialButton(binding.root.context) - button.layoutParams = buttonLayout - button.setupToggle(ArrayProperty(voice.noteActive[column], row), R.color.blue) - rowLayout.addView(button) - } - binding.noteGrid.addView(rowLayout) - } - binding.noteGrid.isStretchAllColumns = true - binding.closeButton.setOnClickListener { - dismiss() - } - return binding.root - } - - override fun onStart() { - super.onStart() - dialog?.window?.setLayout( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - ) - } - - companion object { - val buttonLayout = TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT) - - init { - buttonLayout.setMargins(5) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt index 75c1545..b310c72 100644 --- a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt +++ b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt @@ -36,6 +36,10 @@ if (this::task.isInitialized) { task.cancel() } - task = timer.schedule((60000 / tempo).toLong(), (60000 / tempo).toLong(), callback) + task = timer.schedule( + (60000 / tempo / Song.currentSong.subBeats).toLong(), + (60000 / tempo / Song.currentSong.subBeats).toLong(), + callback + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Song.kt b/app/src/main/java/com/lukas/music/song/Song.kt index fc5421b..5046664 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -14,11 +14,13 @@ import com.lukas.music.song.chords.ChordProgression import com.lukas.music.song.note.Note import com.lukas.music.util.Cycle +import com.lukas.music.util.MetaCycle class Song( root: Note, - val beats: Int -) : Cycle(beats) { + val beats: Int, + val subBeats: Int, +) : MetaCycle>() { val chordProgression = ChordProgression() var soloInstrument: Instrument? = null set(value) { @@ -46,7 +48,11 @@ init { for (i in 0 until beats) { - this += i + val cycle = Cycle() + for (j in 0 until subBeats) { + cycle += j + } + this += cycle } wraparoundListeners += { chordProgression.step() @@ -54,24 +60,25 @@ } } - override fun step(): Int { + override fun step(): Cycle? { super.step() - val chord = chordProgression.currentItem?.currentItem ?: return index + val chord = chordProgression.currentItem?.currentItem ?: return currentItem val chordNotes = chord.getNotes(root) soloInstrument?.let { - it.voice.step(root, chordNotes, index) + it.voice.step(root, chordNotes, index, currentItem!!.index) } ?: run { for (instrument in Instrument.instruments) { - instrument.voice.step(root, chordNotes, index) + instrument.voice.step(root, chordNotes, index, currentItem!!.index) } } - return index + return currentItem } companion object { var currentSong = Song( Note.NOTES[69], - 4 + 4, + 2, ) } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt b/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt index 4706068..66650a2 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 @@ -14,14 +14,7 @@ import com.lukas.music.song.note.Note class BassVoice(instrument: Instrument) : Voice(instrument) { - override var noteActive: Array> = arrayOf( - arrayOf(true), - arrayOf(false), - arrayOf(true), - arrayOf(false) - ) - - override val noteCount: Int = 1 + override val noteCount: Int get() = 1 override fun getNotes(root: Note, chordNotes: Array): Array { return arrayOf(chordNotes[0] - 24) 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 index ab7117f..9a075bc 100644 --- a/app/src/main/java/com/lukas/music/song/voice/ChordVoice.kt +++ b/app/src/main/java/com/lukas/music/song/voice/ChordVoice.kt @@ -14,13 +14,7 @@ import com.lukas.music.song.note.Note class ChordVoice(instrument: Instrument) : Voice(instrument) { - override var noteActive: Array> = arrayOf( - Array(3) { false }, - Array(3) { true }, - Array(3) { false }, - Array(3) { true }, - ) - override val noteCount: Int = 3 + override val noteCount: Int get() = 3 override fun getNotes(root: Note, chordNotes: Array): Array { return chordNotes diff --git a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt b/app/src/main/java/com/lukas/music/EditVoiceFragment.kt deleted file mode 100644 index 56f21e6..0000000 --- a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2022 Lukas Eisenhauer - * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or(at your option) any later version. - * - * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If not, see . - */ - -package com.lukas.music - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TableRow -import androidx.core.view.setMargins -import androidx.fragment.app.DialogFragment -import com.google.android.material.button.MaterialButton -import com.lukas.music.databinding.FragmentEditVoiceBinding -import com.lukas.music.song.Song -import com.lukas.music.song.voice.Voice -import com.lukas.music.util.ArrayProperty -import com.lukas.music.util.setupToggle - -class EditVoiceFragment(private val voice: Voice) : DialogFragment() { - private lateinit var binding: FragmentEditVoiceBinding - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - binding = FragmentEditVoiceBinding.inflate(inflater) - for (row in 0 until voice.noteCount) { - val rowLayout = TableRow(binding.root.context) - for (column in 0 until Song.currentSong.beats) { - val button = MaterialButton(binding.root.context) - button.layoutParams = buttonLayout - button.setupToggle(ArrayProperty(voice.noteActive[column], row), R.color.blue) - rowLayout.addView(button) - } - binding.noteGrid.addView(rowLayout) - } - binding.noteGrid.isStretchAllColumns = true - binding.closeButton.setOnClickListener { - dismiss() - } - return binding.root - } - - override fun onStart() { - super.onStart() - dialog?.window?.setLayout( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - ) - } - - companion object { - val buttonLayout = TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT) - - init { - buttonLayout.setMargins(5) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt index 75c1545..b310c72 100644 --- a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt +++ b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt @@ -36,6 +36,10 @@ if (this::task.isInitialized) { task.cancel() } - task = timer.schedule((60000 / tempo).toLong(), (60000 / tempo).toLong(), callback) + task = timer.schedule( + (60000 / tempo / Song.currentSong.subBeats).toLong(), + (60000 / tempo / Song.currentSong.subBeats).toLong(), + callback + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Song.kt b/app/src/main/java/com/lukas/music/song/Song.kt index fc5421b..5046664 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -14,11 +14,13 @@ import com.lukas.music.song.chords.ChordProgression import com.lukas.music.song.note.Note import com.lukas.music.util.Cycle +import com.lukas.music.util.MetaCycle class Song( root: Note, - val beats: Int -) : Cycle(beats) { + val beats: Int, + val subBeats: Int, +) : MetaCycle>() { val chordProgression = ChordProgression() var soloInstrument: Instrument? = null set(value) { @@ -46,7 +48,11 @@ init { for (i in 0 until beats) { - this += i + val cycle = Cycle() + for (j in 0 until subBeats) { + cycle += j + } + this += cycle } wraparoundListeners += { chordProgression.step() @@ -54,24 +60,25 @@ } } - override fun step(): Int { + override fun step(): Cycle? { super.step() - val chord = chordProgression.currentItem?.currentItem ?: return index + val chord = chordProgression.currentItem?.currentItem ?: return currentItem val chordNotes = chord.getNotes(root) soloInstrument?.let { - it.voice.step(root, chordNotes, index) + it.voice.step(root, chordNotes, index, currentItem!!.index) } ?: run { for (instrument in Instrument.instruments) { - instrument.voice.step(root, chordNotes, index) + instrument.voice.step(root, chordNotes, index, currentItem!!.index) } } - return index + return currentItem } companion object { var currentSong = Song( Note.NOTES[69], - 4 + 4, + 2, ) } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt b/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt index 4706068..66650a2 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 @@ -14,14 +14,7 @@ import com.lukas.music.song.note.Note class BassVoice(instrument: Instrument) : Voice(instrument) { - override var noteActive: Array> = arrayOf( - arrayOf(true), - arrayOf(false), - arrayOf(true), - arrayOf(false) - ) - - override val noteCount: Int = 1 + override val noteCount: Int get() = 1 override fun getNotes(root: Note, chordNotes: Array): Array { return arrayOf(chordNotes[0] - 24) 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 index ab7117f..9a075bc 100644 --- a/app/src/main/java/com/lukas/music/song/voice/ChordVoice.kt +++ b/app/src/main/java/com/lukas/music/song/voice/ChordVoice.kt @@ -14,13 +14,7 @@ import com.lukas.music.song.note.Note class ChordVoice(instrument: Instrument) : Voice(instrument) { - override var noteActive: Array> = arrayOf( - Array(3) { false }, - Array(3) { true }, - Array(3) { false }, - Array(3) { true }, - ) - override val noteCount: Int = 3 + override val noteCount: Int get() = 3 override fun getNotes(root: Note, chordNotes: Array): Array { return chordNotes 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 4f56c2a..54cfe7a 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 @@ -11,20 +11,24 @@ package com.lukas.music.song.voice import com.lukas.music.instruments.Instrument +import com.lukas.music.song.Song import com.lukas.music.song.note.Note import kotlin.reflect.KClass abstract class Voice(val instrument: Instrument) { - abstract var noteActive: Array> abstract val noteCount: Int + val noteActive: Array> = + Array(Song.currentSong.beats * Song.currentSong.subBeats) { Array(noteCount) { false } } + var repeatNote = true // TODO abstract fun getNotes(root: Note, chordNotes: Array): Array - fun step(root: Note, chordNotes: Array, beat: Int) { + fun step(root: Note, chordNotes: Array, beat: Int, subBeat: Int) { if (instrument.muted) { return } - val activeNotes = noteActive[beat] + val beatIndex = beat * Song.currentSong.subBeats + subBeat + val activeNotes = noteActive[beatIndex] val notes = getNotes(root, chordNotes) for ((index, active) in activeNotes.withIndex()) { val note = notes[index] diff --git a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt b/app/src/main/java/com/lukas/music/EditVoiceFragment.kt deleted file mode 100644 index 56f21e6..0000000 --- a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2022 Lukas Eisenhauer - * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or(at your option) any later version. - * - * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If not, see . - */ - -package com.lukas.music - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TableRow -import androidx.core.view.setMargins -import androidx.fragment.app.DialogFragment -import com.google.android.material.button.MaterialButton -import com.lukas.music.databinding.FragmentEditVoiceBinding -import com.lukas.music.song.Song -import com.lukas.music.song.voice.Voice -import com.lukas.music.util.ArrayProperty -import com.lukas.music.util.setupToggle - -class EditVoiceFragment(private val voice: Voice) : DialogFragment() { - private lateinit var binding: FragmentEditVoiceBinding - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - binding = FragmentEditVoiceBinding.inflate(inflater) - for (row in 0 until voice.noteCount) { - val rowLayout = TableRow(binding.root.context) - for (column in 0 until Song.currentSong.beats) { - val button = MaterialButton(binding.root.context) - button.layoutParams = buttonLayout - button.setupToggle(ArrayProperty(voice.noteActive[column], row), R.color.blue) - rowLayout.addView(button) - } - binding.noteGrid.addView(rowLayout) - } - binding.noteGrid.isStretchAllColumns = true - binding.closeButton.setOnClickListener { - dismiss() - } - return binding.root - } - - override fun onStart() { - super.onStart() - dialog?.window?.setLayout( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - ) - } - - companion object { - val buttonLayout = TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT) - - init { - buttonLayout.setMargins(5) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt index 75c1545..b310c72 100644 --- a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt +++ b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt @@ -36,6 +36,10 @@ if (this::task.isInitialized) { task.cancel() } - task = timer.schedule((60000 / tempo).toLong(), (60000 / tempo).toLong(), callback) + task = timer.schedule( + (60000 / tempo / Song.currentSong.subBeats).toLong(), + (60000 / tempo / Song.currentSong.subBeats).toLong(), + callback + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Song.kt b/app/src/main/java/com/lukas/music/song/Song.kt index fc5421b..5046664 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -14,11 +14,13 @@ import com.lukas.music.song.chords.ChordProgression import com.lukas.music.song.note.Note import com.lukas.music.util.Cycle +import com.lukas.music.util.MetaCycle class Song( root: Note, - val beats: Int -) : Cycle(beats) { + val beats: Int, + val subBeats: Int, +) : MetaCycle>() { val chordProgression = ChordProgression() var soloInstrument: Instrument? = null set(value) { @@ -46,7 +48,11 @@ init { for (i in 0 until beats) { - this += i + val cycle = Cycle() + for (j in 0 until subBeats) { + cycle += j + } + this += cycle } wraparoundListeners += { chordProgression.step() @@ -54,24 +60,25 @@ } } - override fun step(): Int { + override fun step(): Cycle? { super.step() - val chord = chordProgression.currentItem?.currentItem ?: return index + val chord = chordProgression.currentItem?.currentItem ?: return currentItem val chordNotes = chord.getNotes(root) soloInstrument?.let { - it.voice.step(root, chordNotes, index) + it.voice.step(root, chordNotes, index, currentItem!!.index) } ?: run { for (instrument in Instrument.instruments) { - instrument.voice.step(root, chordNotes, index) + instrument.voice.step(root, chordNotes, index, currentItem!!.index) } } - return index + return currentItem } companion object { var currentSong = Song( Note.NOTES[69], - 4 + 4, + 2, ) } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt b/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt index 4706068..66650a2 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 @@ -14,14 +14,7 @@ import com.lukas.music.song.note.Note class BassVoice(instrument: Instrument) : Voice(instrument) { - override var noteActive: Array> = arrayOf( - arrayOf(true), - arrayOf(false), - arrayOf(true), - arrayOf(false) - ) - - override val noteCount: Int = 1 + override val noteCount: Int get() = 1 override fun getNotes(root: Note, chordNotes: Array): Array { return arrayOf(chordNotes[0] - 24) 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 index ab7117f..9a075bc 100644 --- a/app/src/main/java/com/lukas/music/song/voice/ChordVoice.kt +++ b/app/src/main/java/com/lukas/music/song/voice/ChordVoice.kt @@ -14,13 +14,7 @@ import com.lukas.music.song.note.Note class ChordVoice(instrument: Instrument) : Voice(instrument) { - override var noteActive: Array> = arrayOf( - Array(3) { false }, - Array(3) { true }, - Array(3) { false }, - Array(3) { true }, - ) - override val noteCount: Int = 3 + override val noteCount: Int get() = 3 override fun getNotes(root: Note, chordNotes: Array): Array { return chordNotes 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 4f56c2a..54cfe7a 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 @@ -11,20 +11,24 @@ package com.lukas.music.song.voice import com.lukas.music.instruments.Instrument +import com.lukas.music.song.Song import com.lukas.music.song.note.Note import kotlin.reflect.KClass abstract class Voice(val instrument: Instrument) { - abstract var noteActive: Array> abstract val noteCount: Int + val noteActive: Array> = + Array(Song.currentSong.beats * Song.currentSong.subBeats) { Array(noteCount) { false } } + var repeatNote = true // TODO abstract fun getNotes(root: Note, chordNotes: Array): Array - fun step(root: Note, chordNotes: Array, beat: Int) { + fun step(root: Note, chordNotes: Array, beat: Int, subBeat: Int) { if (instrument.muted) { return } - val activeNotes = noteActive[beat] + val beatIndex = beat * Song.currentSong.subBeats + subBeat + val activeNotes = noteActive[beatIndex] val notes = getNotes(root, chordNotes) for ((index, active) in activeNotes.withIndex()) { val note = notes[index] diff --git a/app/src/main/java/com/lukas/music/ui/fragments/EditInstrumentFragment.kt b/app/src/main/java/com/lukas/music/ui/fragments/EditInstrumentFragment.kt index 0020ae8..9c76f59 100644 --- a/app/src/main/java/com/lukas/music/ui/fragments/EditInstrumentFragment.kt +++ b/app/src/main/java/com/lukas/music/ui/fragments/EditInstrumentFragment.kt @@ -17,7 +17,6 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.DialogFragment -import com.lukas.music.EditVoiceFragment import com.lukas.music.databinding.FragmentEditInstrumentBinding import com.lukas.music.instruments.Instrument import com.lukas.music.instruments.Waveform diff --git a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt b/app/src/main/java/com/lukas/music/EditVoiceFragment.kt deleted file mode 100644 index 56f21e6..0000000 --- a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2022 Lukas Eisenhauer - * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or(at your option) any later version. - * - * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If not, see . - */ - -package com.lukas.music - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TableRow -import androidx.core.view.setMargins -import androidx.fragment.app.DialogFragment -import com.google.android.material.button.MaterialButton -import com.lukas.music.databinding.FragmentEditVoiceBinding -import com.lukas.music.song.Song -import com.lukas.music.song.voice.Voice -import com.lukas.music.util.ArrayProperty -import com.lukas.music.util.setupToggle - -class EditVoiceFragment(private val voice: Voice) : DialogFragment() { - private lateinit var binding: FragmentEditVoiceBinding - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - binding = FragmentEditVoiceBinding.inflate(inflater) - for (row in 0 until voice.noteCount) { - val rowLayout = TableRow(binding.root.context) - for (column in 0 until Song.currentSong.beats) { - val button = MaterialButton(binding.root.context) - button.layoutParams = buttonLayout - button.setupToggle(ArrayProperty(voice.noteActive[column], row), R.color.blue) - rowLayout.addView(button) - } - binding.noteGrid.addView(rowLayout) - } - binding.noteGrid.isStretchAllColumns = true - binding.closeButton.setOnClickListener { - dismiss() - } - return binding.root - } - - override fun onStart() { - super.onStart() - dialog?.window?.setLayout( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - ) - } - - companion object { - val buttonLayout = TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT) - - init { - buttonLayout.setMargins(5) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt index 75c1545..b310c72 100644 --- a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt +++ b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt @@ -36,6 +36,10 @@ if (this::task.isInitialized) { task.cancel() } - task = timer.schedule((60000 / tempo).toLong(), (60000 / tempo).toLong(), callback) + task = timer.schedule( + (60000 / tempo / Song.currentSong.subBeats).toLong(), + (60000 / tempo / Song.currentSong.subBeats).toLong(), + callback + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Song.kt b/app/src/main/java/com/lukas/music/song/Song.kt index fc5421b..5046664 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -14,11 +14,13 @@ import com.lukas.music.song.chords.ChordProgression import com.lukas.music.song.note.Note import com.lukas.music.util.Cycle +import com.lukas.music.util.MetaCycle class Song( root: Note, - val beats: Int -) : Cycle(beats) { + val beats: Int, + val subBeats: Int, +) : MetaCycle>() { val chordProgression = ChordProgression() var soloInstrument: Instrument? = null set(value) { @@ -46,7 +48,11 @@ init { for (i in 0 until beats) { - this += i + val cycle = Cycle() + for (j in 0 until subBeats) { + cycle += j + } + this += cycle } wraparoundListeners += { chordProgression.step() @@ -54,24 +60,25 @@ } } - override fun step(): Int { + override fun step(): Cycle? { super.step() - val chord = chordProgression.currentItem?.currentItem ?: return index + val chord = chordProgression.currentItem?.currentItem ?: return currentItem val chordNotes = chord.getNotes(root) soloInstrument?.let { - it.voice.step(root, chordNotes, index) + it.voice.step(root, chordNotes, index, currentItem!!.index) } ?: run { for (instrument in Instrument.instruments) { - instrument.voice.step(root, chordNotes, index) + instrument.voice.step(root, chordNotes, index, currentItem!!.index) } } - return index + return currentItem } companion object { var currentSong = Song( Note.NOTES[69], - 4 + 4, + 2, ) } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt b/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt index 4706068..66650a2 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 @@ -14,14 +14,7 @@ import com.lukas.music.song.note.Note class BassVoice(instrument: Instrument) : Voice(instrument) { - override var noteActive: Array> = arrayOf( - arrayOf(true), - arrayOf(false), - arrayOf(true), - arrayOf(false) - ) - - override val noteCount: Int = 1 + override val noteCount: Int get() = 1 override fun getNotes(root: Note, chordNotes: Array): Array { return arrayOf(chordNotes[0] - 24) 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 index ab7117f..9a075bc 100644 --- a/app/src/main/java/com/lukas/music/song/voice/ChordVoice.kt +++ b/app/src/main/java/com/lukas/music/song/voice/ChordVoice.kt @@ -14,13 +14,7 @@ import com.lukas.music.song.note.Note class ChordVoice(instrument: Instrument) : Voice(instrument) { - override var noteActive: Array> = arrayOf( - Array(3) { false }, - Array(3) { true }, - Array(3) { false }, - Array(3) { true }, - ) - override val noteCount: Int = 3 + override val noteCount: Int get() = 3 override fun getNotes(root: Note, chordNotes: Array): Array { return chordNotes 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 4f56c2a..54cfe7a 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 @@ -11,20 +11,24 @@ package com.lukas.music.song.voice import com.lukas.music.instruments.Instrument +import com.lukas.music.song.Song import com.lukas.music.song.note.Note import kotlin.reflect.KClass abstract class Voice(val instrument: Instrument) { - abstract var noteActive: Array> abstract val noteCount: Int + val noteActive: Array> = + Array(Song.currentSong.beats * Song.currentSong.subBeats) { Array(noteCount) { false } } + var repeatNote = true // TODO abstract fun getNotes(root: Note, chordNotes: Array): Array - fun step(root: Note, chordNotes: Array, beat: Int) { + fun step(root: Note, chordNotes: Array, beat: Int, subBeat: Int) { if (instrument.muted) { return } - val activeNotes = noteActive[beat] + val beatIndex = beat * Song.currentSong.subBeats + subBeat + val activeNotes = noteActive[beatIndex] val notes = getNotes(root, chordNotes) for ((index, active) in activeNotes.withIndex()) { val note = notes[index] diff --git a/app/src/main/java/com/lukas/music/ui/fragments/EditInstrumentFragment.kt b/app/src/main/java/com/lukas/music/ui/fragments/EditInstrumentFragment.kt index 0020ae8..9c76f59 100644 --- a/app/src/main/java/com/lukas/music/ui/fragments/EditInstrumentFragment.kt +++ b/app/src/main/java/com/lukas/music/ui/fragments/EditInstrumentFragment.kt @@ -17,7 +17,6 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.DialogFragment -import com.lukas.music.EditVoiceFragment import com.lukas.music.databinding.FragmentEditInstrumentBinding import com.lukas.music.instruments.Instrument import com.lukas.music.instruments.Waveform diff --git a/app/src/main/java/com/lukas/music/ui/fragments/EditVoiceFragment.kt b/app/src/main/java/com/lukas/music/ui/fragments/EditVoiceFragment.kt new file mode 100644 index 0000000..58a856f --- /dev/null +++ b/app/src/main/java/com/lukas/music/ui/fragments/EditVoiceFragment.kt @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2022 Lukas Eisenhauer + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or(at your option) any later version. + * + * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + */ + +package com.lukas.music.ui.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TableRow +import androidx.core.view.setMargins +import androidx.fragment.app.DialogFragment +import com.google.android.material.button.MaterialButton +import com.lukas.music.R +import com.lukas.music.databinding.FragmentEditVoiceBinding +import com.lukas.music.song.Song +import com.lukas.music.song.voice.Voice +import com.lukas.music.util.ArrayProperty +import com.lukas.music.util.setupToggle + +class EditVoiceFragment(private val voice: Voice) : DialogFragment() { + private lateinit var binding: FragmentEditVoiceBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentEditVoiceBinding.inflate(inflater) + for (row in voice.noteCount - 1 downTo 0) { + val rowLayout = TableRow(binding.root.context) + for (column in 0 until Song.currentSong.beats * Song.currentSong.subBeats) { + val button = MaterialButton(binding.root.context) + button.layoutParams = buttonLayout + button.setupToggle( + ArrayProperty(voice.noteActive[column], row), + R.color.blue, + inactiveColor = if (column % Song.currentSong.subBeats == 0) R.color.gray_0x50 else R.color.gray_0x70 + ) + rowLayout.addView(button) + } + binding.noteGrid.addView(rowLayout) + } + binding.noteGrid.isStretchAllColumns = true + binding.closeButton.setOnClickListener { + dismiss() + } + return binding.root + } + + override fun onStart() { + super.onStart() + dialog?.window?.setLayout( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + } + + companion object { + val buttonLayout = TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT) + + init { + buttonLayout.setMargins(5) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt b/app/src/main/java/com/lukas/music/EditVoiceFragment.kt deleted file mode 100644 index 56f21e6..0000000 --- a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2022 Lukas Eisenhauer - * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or(at your option) any later version. - * - * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If not, see . - */ - -package com.lukas.music - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TableRow -import androidx.core.view.setMargins -import androidx.fragment.app.DialogFragment -import com.google.android.material.button.MaterialButton -import com.lukas.music.databinding.FragmentEditVoiceBinding -import com.lukas.music.song.Song -import com.lukas.music.song.voice.Voice -import com.lukas.music.util.ArrayProperty -import com.lukas.music.util.setupToggle - -class EditVoiceFragment(private val voice: Voice) : DialogFragment() { - private lateinit var binding: FragmentEditVoiceBinding - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - binding = FragmentEditVoiceBinding.inflate(inflater) - for (row in 0 until voice.noteCount) { - val rowLayout = TableRow(binding.root.context) - for (column in 0 until Song.currentSong.beats) { - val button = MaterialButton(binding.root.context) - button.layoutParams = buttonLayout - button.setupToggle(ArrayProperty(voice.noteActive[column], row), R.color.blue) - rowLayout.addView(button) - } - binding.noteGrid.addView(rowLayout) - } - binding.noteGrid.isStretchAllColumns = true - binding.closeButton.setOnClickListener { - dismiss() - } - return binding.root - } - - override fun onStart() { - super.onStart() - dialog?.window?.setLayout( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - ) - } - - companion object { - val buttonLayout = TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT) - - init { - buttonLayout.setMargins(5) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt index 75c1545..b310c72 100644 --- a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt +++ b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt @@ -36,6 +36,10 @@ if (this::task.isInitialized) { task.cancel() } - task = timer.schedule((60000 / tempo).toLong(), (60000 / tempo).toLong(), callback) + task = timer.schedule( + (60000 / tempo / Song.currentSong.subBeats).toLong(), + (60000 / tempo / Song.currentSong.subBeats).toLong(), + callback + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Song.kt b/app/src/main/java/com/lukas/music/song/Song.kt index fc5421b..5046664 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -14,11 +14,13 @@ import com.lukas.music.song.chords.ChordProgression import com.lukas.music.song.note.Note import com.lukas.music.util.Cycle +import com.lukas.music.util.MetaCycle class Song( root: Note, - val beats: Int -) : Cycle(beats) { + val beats: Int, + val subBeats: Int, +) : MetaCycle>() { val chordProgression = ChordProgression() var soloInstrument: Instrument? = null set(value) { @@ -46,7 +48,11 @@ init { for (i in 0 until beats) { - this += i + val cycle = Cycle() + for (j in 0 until subBeats) { + cycle += j + } + this += cycle } wraparoundListeners += { chordProgression.step() @@ -54,24 +60,25 @@ } } - override fun step(): Int { + override fun step(): Cycle? { super.step() - val chord = chordProgression.currentItem?.currentItem ?: return index + val chord = chordProgression.currentItem?.currentItem ?: return currentItem val chordNotes = chord.getNotes(root) soloInstrument?.let { - it.voice.step(root, chordNotes, index) + it.voice.step(root, chordNotes, index, currentItem!!.index) } ?: run { for (instrument in Instrument.instruments) { - instrument.voice.step(root, chordNotes, index) + instrument.voice.step(root, chordNotes, index, currentItem!!.index) } } - return index + return currentItem } companion object { var currentSong = Song( Note.NOTES[69], - 4 + 4, + 2, ) } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt b/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt index 4706068..66650a2 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 @@ -14,14 +14,7 @@ import com.lukas.music.song.note.Note class BassVoice(instrument: Instrument) : Voice(instrument) { - override var noteActive: Array> = arrayOf( - arrayOf(true), - arrayOf(false), - arrayOf(true), - arrayOf(false) - ) - - override val noteCount: Int = 1 + override val noteCount: Int get() = 1 override fun getNotes(root: Note, chordNotes: Array): Array { return arrayOf(chordNotes[0] - 24) 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 index ab7117f..9a075bc 100644 --- a/app/src/main/java/com/lukas/music/song/voice/ChordVoice.kt +++ b/app/src/main/java/com/lukas/music/song/voice/ChordVoice.kt @@ -14,13 +14,7 @@ import com.lukas.music.song.note.Note class ChordVoice(instrument: Instrument) : Voice(instrument) { - override var noteActive: Array> = arrayOf( - Array(3) { false }, - Array(3) { true }, - Array(3) { false }, - Array(3) { true }, - ) - override val noteCount: Int = 3 + override val noteCount: Int get() = 3 override fun getNotes(root: Note, chordNotes: Array): Array { return chordNotes 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 4f56c2a..54cfe7a 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 @@ -11,20 +11,24 @@ package com.lukas.music.song.voice import com.lukas.music.instruments.Instrument +import com.lukas.music.song.Song import com.lukas.music.song.note.Note import kotlin.reflect.KClass abstract class Voice(val instrument: Instrument) { - abstract var noteActive: Array> abstract val noteCount: Int + val noteActive: Array> = + Array(Song.currentSong.beats * Song.currentSong.subBeats) { Array(noteCount) { false } } + var repeatNote = true // TODO abstract fun getNotes(root: Note, chordNotes: Array): Array - fun step(root: Note, chordNotes: Array, beat: Int) { + fun step(root: Note, chordNotes: Array, beat: Int, subBeat: Int) { if (instrument.muted) { return } - val activeNotes = noteActive[beat] + val beatIndex = beat * Song.currentSong.subBeats + subBeat + val activeNotes = noteActive[beatIndex] val notes = getNotes(root, chordNotes) for ((index, active) in activeNotes.withIndex()) { val note = notes[index] diff --git a/app/src/main/java/com/lukas/music/ui/fragments/EditInstrumentFragment.kt b/app/src/main/java/com/lukas/music/ui/fragments/EditInstrumentFragment.kt index 0020ae8..9c76f59 100644 --- a/app/src/main/java/com/lukas/music/ui/fragments/EditInstrumentFragment.kt +++ b/app/src/main/java/com/lukas/music/ui/fragments/EditInstrumentFragment.kt @@ -17,7 +17,6 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.DialogFragment -import com.lukas.music.EditVoiceFragment import com.lukas.music.databinding.FragmentEditInstrumentBinding import com.lukas.music.instruments.Instrument import com.lukas.music.instruments.Waveform diff --git a/app/src/main/java/com/lukas/music/ui/fragments/EditVoiceFragment.kt b/app/src/main/java/com/lukas/music/ui/fragments/EditVoiceFragment.kt new file mode 100644 index 0000000..58a856f --- /dev/null +++ b/app/src/main/java/com/lukas/music/ui/fragments/EditVoiceFragment.kt @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2022 Lukas Eisenhauer + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or(at your option) any later version. + * + * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + */ + +package com.lukas.music.ui.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TableRow +import androidx.core.view.setMargins +import androidx.fragment.app.DialogFragment +import com.google.android.material.button.MaterialButton +import com.lukas.music.R +import com.lukas.music.databinding.FragmentEditVoiceBinding +import com.lukas.music.song.Song +import com.lukas.music.song.voice.Voice +import com.lukas.music.util.ArrayProperty +import com.lukas.music.util.setupToggle + +class EditVoiceFragment(private val voice: Voice) : DialogFragment() { + private lateinit var binding: FragmentEditVoiceBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentEditVoiceBinding.inflate(inflater) + for (row in voice.noteCount - 1 downTo 0) { + val rowLayout = TableRow(binding.root.context) + for (column in 0 until Song.currentSong.beats * Song.currentSong.subBeats) { + val button = MaterialButton(binding.root.context) + button.layoutParams = buttonLayout + button.setupToggle( + ArrayProperty(voice.noteActive[column], row), + R.color.blue, + inactiveColor = if (column % Song.currentSong.subBeats == 0) R.color.gray_0x50 else R.color.gray_0x70 + ) + rowLayout.addView(button) + } + binding.noteGrid.addView(rowLayout) + } + binding.noteGrid.isStretchAllColumns = true + binding.closeButton.setOnClickListener { + dismiss() + } + return binding.root + } + + override fun onStart() { + super.onStart() + dialog?.window?.setLayout( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + } + + companion object { + val buttonLayout = TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT) + + init { + buttonLayout.setMargins(5) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/util/UIUtil.kt b/app/src/main/java/com/lukas/music/util/UIUtil.kt index da897c5..e7ba28f 100644 --- a/app/src/main/java/com/lukas/music/util/UIUtil.kt +++ b/app/src/main/java/com/lukas/music/util/UIUtil.kt @@ -42,19 +42,24 @@ fun Button.setupToggle( target: KMutableProperty0, activeColor: Int, - callback: (Boolean) -> Unit = {} + inactiveColor: Int = R.color.gray_0x60, + callback: (Boolean) -> Unit = {}, ) { setOnClickListener { target.set(!target.get()) - updateToggle(target, activeColor) + updateToggle(target, activeColor, inactiveColor) callback(target.get()) } - updateToggle(target, activeColor) + updateToggle(target, activeColor, inactiveColor) } -fun Button.updateToggle(target: KMutableProperty0, activeColor: Int) { +fun Button.updateToggle( + target: KMutableProperty0, + activeColor: Int, + inactiveColor: Int = R.color.gray_0x60, +) { setBackgroundColor( - ContextCompat.getColor(context, if (target.get()) activeColor else R.color.gray_0x60) + ContextCompat.getColor(context, if (target.get()) activeColor else inactiveColor) ) } diff --git a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt b/app/src/main/java/com/lukas/music/EditVoiceFragment.kt deleted file mode 100644 index 56f21e6..0000000 --- a/app/src/main/java/com/lukas/music/EditVoiceFragment.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2022 Lukas Eisenhauer - * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or(at your option) any later version. - * - * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If not, see . - */ - -package com.lukas.music - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TableRow -import androidx.core.view.setMargins -import androidx.fragment.app.DialogFragment -import com.google.android.material.button.MaterialButton -import com.lukas.music.databinding.FragmentEditVoiceBinding -import com.lukas.music.song.Song -import com.lukas.music.song.voice.Voice -import com.lukas.music.util.ArrayProperty -import com.lukas.music.util.setupToggle - -class EditVoiceFragment(private val voice: Voice) : DialogFragment() { - private lateinit var binding: FragmentEditVoiceBinding - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - binding = FragmentEditVoiceBinding.inflate(inflater) - for (row in 0 until voice.noteCount) { - val rowLayout = TableRow(binding.root.context) - for (column in 0 until Song.currentSong.beats) { - val button = MaterialButton(binding.root.context) - button.layoutParams = buttonLayout - button.setupToggle(ArrayProperty(voice.noteActive[column], row), R.color.blue) - rowLayout.addView(button) - } - binding.noteGrid.addView(rowLayout) - } - binding.noteGrid.isStretchAllColumns = true - binding.closeButton.setOnClickListener { - dismiss() - } - return binding.root - } - - override fun onStart() { - super.onStart() - dialog?.window?.setLayout( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT - ) - } - - companion object { - val buttonLayout = TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT) - - init { - buttonLayout.setMargins(5) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt index 75c1545..b310c72 100644 --- a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt +++ b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt @@ -36,6 +36,10 @@ if (this::task.isInitialized) { task.cancel() } - task = timer.schedule((60000 / tempo).toLong(), (60000 / tempo).toLong(), callback) + task = timer.schedule( + (60000 / tempo / Song.currentSong.subBeats).toLong(), + (60000 / tempo / Song.currentSong.subBeats).toLong(), + callback + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/Song.kt b/app/src/main/java/com/lukas/music/song/Song.kt index fc5421b..5046664 100644 --- a/app/src/main/java/com/lukas/music/song/Song.kt +++ b/app/src/main/java/com/lukas/music/song/Song.kt @@ -14,11 +14,13 @@ import com.lukas.music.song.chords.ChordProgression import com.lukas.music.song.note.Note import com.lukas.music.util.Cycle +import com.lukas.music.util.MetaCycle class Song( root: Note, - val beats: Int -) : Cycle(beats) { + val beats: Int, + val subBeats: Int, +) : MetaCycle>() { val chordProgression = ChordProgression() var soloInstrument: Instrument? = null set(value) { @@ -46,7 +48,11 @@ init { for (i in 0 until beats) { - this += i + val cycle = Cycle() + for (j in 0 until subBeats) { + cycle += j + } + this += cycle } wraparoundListeners += { chordProgression.step() @@ -54,24 +60,25 @@ } } - override fun step(): Int { + override fun step(): Cycle? { super.step() - val chord = chordProgression.currentItem?.currentItem ?: return index + val chord = chordProgression.currentItem?.currentItem ?: return currentItem val chordNotes = chord.getNotes(root) soloInstrument?.let { - it.voice.step(root, chordNotes, index) + it.voice.step(root, chordNotes, index, currentItem!!.index) } ?: run { for (instrument in Instrument.instruments) { - instrument.voice.step(root, chordNotes, index) + instrument.voice.step(root, chordNotes, index, currentItem!!.index) } } - return index + return currentItem } companion object { var currentSong = Song( Note.NOTES[69], - 4 + 4, + 2, ) } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt b/app/src/main/java/com/lukas/music/song/voice/BassVoice.kt index 4706068..66650a2 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 @@ -14,14 +14,7 @@ import com.lukas.music.song.note.Note class BassVoice(instrument: Instrument) : Voice(instrument) { - override var noteActive: Array> = arrayOf( - arrayOf(true), - arrayOf(false), - arrayOf(true), - arrayOf(false) - ) - - override val noteCount: Int = 1 + override val noteCount: Int get() = 1 override fun getNotes(root: Note, chordNotes: Array): Array { return arrayOf(chordNotes[0] - 24) 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 index ab7117f..9a075bc 100644 --- a/app/src/main/java/com/lukas/music/song/voice/ChordVoice.kt +++ b/app/src/main/java/com/lukas/music/song/voice/ChordVoice.kt @@ -14,13 +14,7 @@ import com.lukas.music.song.note.Note class ChordVoice(instrument: Instrument) : Voice(instrument) { - override var noteActive: Array> = arrayOf( - Array(3) { false }, - Array(3) { true }, - Array(3) { false }, - Array(3) { true }, - ) - override val noteCount: Int = 3 + override val noteCount: Int get() = 3 override fun getNotes(root: Note, chordNotes: Array): Array { return chordNotes 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 4f56c2a..54cfe7a 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 @@ -11,20 +11,24 @@ package com.lukas.music.song.voice import com.lukas.music.instruments.Instrument +import com.lukas.music.song.Song import com.lukas.music.song.note.Note import kotlin.reflect.KClass abstract class Voice(val instrument: Instrument) { - abstract var noteActive: Array> abstract val noteCount: Int + val noteActive: Array> = + Array(Song.currentSong.beats * Song.currentSong.subBeats) { Array(noteCount) { false } } + var repeatNote = true // TODO abstract fun getNotes(root: Note, chordNotes: Array): Array - fun step(root: Note, chordNotes: Array, beat: Int) { + fun step(root: Note, chordNotes: Array, beat: Int, subBeat: Int) { if (instrument.muted) { return } - val activeNotes = noteActive[beat] + val beatIndex = beat * Song.currentSong.subBeats + subBeat + val activeNotes = noteActive[beatIndex] val notes = getNotes(root, chordNotes) for ((index, active) in activeNotes.withIndex()) { val note = notes[index] diff --git a/app/src/main/java/com/lukas/music/ui/fragments/EditInstrumentFragment.kt b/app/src/main/java/com/lukas/music/ui/fragments/EditInstrumentFragment.kt index 0020ae8..9c76f59 100644 --- a/app/src/main/java/com/lukas/music/ui/fragments/EditInstrumentFragment.kt +++ b/app/src/main/java/com/lukas/music/ui/fragments/EditInstrumentFragment.kt @@ -17,7 +17,6 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.DialogFragment -import com.lukas.music.EditVoiceFragment import com.lukas.music.databinding.FragmentEditInstrumentBinding import com.lukas.music.instruments.Instrument import com.lukas.music.instruments.Waveform diff --git a/app/src/main/java/com/lukas/music/ui/fragments/EditVoiceFragment.kt b/app/src/main/java/com/lukas/music/ui/fragments/EditVoiceFragment.kt new file mode 100644 index 0000000..58a856f --- /dev/null +++ b/app/src/main/java/com/lukas/music/ui/fragments/EditVoiceFragment.kt @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2022 Lukas Eisenhauer + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or(at your option) any later version. + * + * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + */ + +package com.lukas.music.ui.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TableRow +import androidx.core.view.setMargins +import androidx.fragment.app.DialogFragment +import com.google.android.material.button.MaterialButton +import com.lukas.music.R +import com.lukas.music.databinding.FragmentEditVoiceBinding +import com.lukas.music.song.Song +import com.lukas.music.song.voice.Voice +import com.lukas.music.util.ArrayProperty +import com.lukas.music.util.setupToggle + +class EditVoiceFragment(private val voice: Voice) : DialogFragment() { + private lateinit var binding: FragmentEditVoiceBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentEditVoiceBinding.inflate(inflater) + for (row in voice.noteCount - 1 downTo 0) { + val rowLayout = TableRow(binding.root.context) + for (column in 0 until Song.currentSong.beats * Song.currentSong.subBeats) { + val button = MaterialButton(binding.root.context) + button.layoutParams = buttonLayout + button.setupToggle( + ArrayProperty(voice.noteActive[column], row), + R.color.blue, + inactiveColor = if (column % Song.currentSong.subBeats == 0) R.color.gray_0x50 else R.color.gray_0x70 + ) + rowLayout.addView(button) + } + binding.noteGrid.addView(rowLayout) + } + binding.noteGrid.isStretchAllColumns = true + binding.closeButton.setOnClickListener { + dismiss() + } + return binding.root + } + + override fun onStart() { + super.onStart() + dialog?.window?.setLayout( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + } + + companion object { + val buttonLayout = TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT) + + init { + buttonLayout.setMargins(5) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/util/UIUtil.kt b/app/src/main/java/com/lukas/music/util/UIUtil.kt index da897c5..e7ba28f 100644 --- a/app/src/main/java/com/lukas/music/util/UIUtil.kt +++ b/app/src/main/java/com/lukas/music/util/UIUtil.kt @@ -42,19 +42,24 @@ fun Button.setupToggle( target: KMutableProperty0, activeColor: Int, - callback: (Boolean) -> Unit = {} + inactiveColor: Int = R.color.gray_0x60, + callback: (Boolean) -> Unit = {}, ) { setOnClickListener { target.set(!target.get()) - updateToggle(target, activeColor) + updateToggle(target, activeColor, inactiveColor) callback(target.get()) } - updateToggle(target, activeColor) + updateToggle(target, activeColor, inactiveColor) } -fun Button.updateToggle(target: KMutableProperty0, activeColor: Int) { +fun Button.updateToggle( + target: KMutableProperty0, + activeColor: Int, + inactiveColor: Int = R.color.gray_0x60, +) { setBackgroundColor( - ContextCompat.getColor(context, if (target.get()) activeColor else R.color.gray_0x60) + ContextCompat.getColor(context, if (target.get()) activeColor else inactiveColor) ) } diff --git a/app/src/main/res/layout/fragment_edit_voice.xml b/app/src/main/res/layout/fragment_edit_voice.xml index b29b2c7..5380d7d 100644 --- a/app/src/main/res/layout/fragment_edit_voice.xml +++ b/app/src/main/res/layout/fragment_edit_voice.xml @@ -14,7 +14,7 @@ android:id="@+id/frameLayout2" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".EditVoiceFragment"> + tools:context=".ui.fragments.EditVoiceFragment">