Newer
Older
music / app / src / main / java / com / lukas / music / song / chords / Chord.kt
/*
 * 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 <https://www.gnu.org/licenses/>.
 */

package com.lukas.music.song.chords

import com.lukas.music.song.Song
import com.lukas.music.song.note.Note

class Chord {
    var accidental = Accidental.None
    val accidentals: Array<Accidental?> = arrayOf(Accidental.None, Accidental.None, null, null)

    var note: Int = 0
        set(value) {
            field = value
            interval = Interval(value)
        }

    var interval = Interval(note)
        set(value) {
            field = value
            if (note != value.distance) {
                note = value.distance
            }
        }

    fun getNotes(root: Note): Array<Note> {
        val result = Array(NOTE_COUNT) { root }
        var resultIndex = 0
        var accidentalIndex = 0
        var octave = 0
        while (resultIndex < NOTE_COUNT) {
            if (accidentalIndex == 0) {
                result[resultIndex] = root + note + 12 * octave + accidental.distance
                resultIndex++
            } else if (accidentals[accidentalIndex - 1] != null) {
                result[resultIndex] = root + note + when (accidentalIndex) {
                    1 -> 4
                    2 -> 7
                    3 -> 10
                    4 -> 14
                    else -> 0
                } + accidentals[accidentalIndex - 1]!!.distance + 12 * octave + accidental.distance
                resultIndex++
            }
            accidentalIndex++
            if (accidentalIndex > accidentals.size) {
                octave++
                accidentalIndex = 0
            }
        }
        return result
    }

    override fun toString(): String {
        return toString(false, Song.currentSong.root)
    }

    fun toString(displayChordNames: Boolean, root: Note): String {
        var result = if (displayChordNames) {
            (root + note + accidental.distance).noteName.toString()
        } else {
            interval.toString()
        }
        accidentals[0]?.let {
            result += when (it) {
                Accidental.Flat -> "-"
                Accidental.Sharp -> "sus4"
                else -> ""
            }
        }
        accidentals[1]?.let {
            if (accidentals[0] != null && it == Accidental.None) {
                return@let
            }
            result += it.short + "5"
        }
        result = result.replace("-b5", "0")
        result = result.replace("(?=[A-G])#5".toRegex(), "+")
        accidentals[2]?.let {
            result += when (it) {
                Accidental.Sharp -> " maj7"
                Accidental.None -> " 7"
                Accidental.Flat -> " 6"
            }
        }
        accidentals[3]?.let {
            result += when (it) {
                Accidental.Sharp -> " maj9"
                Accidental.None -> " 9"
                Accidental.Flat -> " b9"
            }
        }
        return result
    }

    companion object {
        const val NOTE_COUNT = 5
    }
}