All Projects → chRyNaN → chords

chRyNaN / chords

Licence: Apache-2.0 license
A Kotlin multi-platform view library for displaying stringed instrument chord diagrams

Programming Languages

kotlin
9241 projects
HTML
75241 projects

Projects that are alternatives of or similar to chords

CliChords
[CliChords] Get ultimate-guitar.com guitar tabs and chords in your terminal - command line cli
Stars: ✭ 20 (-20%)
Mutual labels:  tabs, guitar, chords, guitar-tabs, guitar-chords
Tabdown
Tabdown is an open mark-up language for text tabs & chords.
Stars: ✭ 49 (+96%)
Mutual labels:  tabs, guitar, chords, guitar-chords
guitar-tabs-to-MIDI
A program that converts Guitar Tabs into MIDI files.
Stars: ✭ 38 (+52%)
Mutual labels:  tabs, guitar, guitar-tabs
Chord-Draw
Draw guitar chord diagrams for all variations of any chord and also display finger positions etc.
Stars: ✭ 17 (-32%)
Mutual labels:  guitar, guitar-chords, chord-diagram
Chord-Provider
A Chordpro parser/editor in SwiftUI 4 for macOS and iOS
Stars: ✭ 20 (-20%)
Mutual labels:  guitar, chords, guitar-chords
guitar-book
Open Source, Gatsby theme, mobile and SEO friendly with PWA for building guitar/song books. 🎸 🎤 🎵
Stars: ✭ 29 (+16%)
Mutual labels:  chords, guitar-chords
inject
A simple Kotlin multi-platform abstraction around the javax.inject annotations.
Stars: ✭ 42 (+68%)
Mutual labels:  kotlin-multiplatform, kotlin-multi-platform
guitar
🎸 Online guitar toy and tablature recorder/player
Stars: ✭ 80 (+220%)
Mutual labels:  tabs, guitar
2p-kt
A Kotlin Multi-Platform ecosystem for symbolic AI
Stars: ✭ 52 (+108%)
Mutual labels:  kotlin-multiplatform, kotlin-multi-platform
tabs
Guitar tabs transcribed by me, primarily in the stoner/doom/sludge metal genres... plus a few random other things.
Stars: ✭ 34 (+36%)
Mutual labels:  tabs, guitar
embed-client
🎼 Sheet Music & Tabs Embed JavaScript Client
Stars: ✭ 43 (+72%)
Mutual labels:  music-composition, tabs
Koin
Koin - a pragmatic lightweight dependency injection framework for Kotlin
Stars: ✭ 7,142 (+28468%)
Mutual labels:  kotlin-multiplatform, kotlin-multiplatform-library
Aboutlibraries
AboutLibraries automatically detects all dependencies of a project and collects their information including the license. Optionally visualising it via the provided ui components.
Stars: ✭ 2,777 (+11008%)
Mutual labels:  kotlin-multiplatform, kotlin-multiplatform-library
IndicatorView
IndicatorView Library For Android
Stars: ✭ 41 (+64%)
Mutual labels:  view, tabs
arpeggio
A chord naming app for guitar written in React.
Stars: ✭ 49 (+96%)
Mutual labels:  guitar, chords
serialization-parcelable
Android Parcelable support for the Kotlinx Serialization library.
Stars: ✭ 53 (+112%)
Mutual labels:  kotlin-multiplatform, kotlin-multiplatform-library
realm-kotlin-samples
Samples demonstrating the usage of Realm-Kotlin SDK
Stars: ✭ 50 (+100%)
Mutual labels:  kotlin-multiplatform, kotlin-multiplatform-library
kotlin-multiplatform-example
A Kotlin multiplatform example app that targets Android, ReactJS, iOS, JavaFx, and Spring Boot
Stars: ✭ 115 (+360%)
Mutual labels:  kotlin-multiplatform, kotlin-multi-platform
cursive-tabs
Tabs for gyscos/cursive views 🖥️
Stars: ✭ 21 (-16%)
Mutual labels:  view, tabs
phptabs
A PHP library for reading, writing and rendering guitar tablatures and MIDI files
Stars: ✭ 34 (+36%)
Mutual labels:  guitar, chords

chords

An easily customizable Kotlin multi-platform View to display guitar (and other stringed instrument) chords. Simple to use and beautifully designed.

Current Version: GitHub tag (latest by date)

Sample Screenshot Sample Screenshot

This library has been updated significantly from its original version and the process is detailed in this blog post which was featured in Android Weekly issue #398. Badge

Building the library

The library is provided through Repsy.io. Checkout the releases page to get the latest version.
GitHub tag (latest by date)

Repository

repositories {
    maven { url = uri("https://repo.repsy.io/mvn/chrynan/public") }
}

Dependencies

core:

implementation("com.chrynan.chords:chords-core:VERSION")

compose:

implementation("com.chrynan.chords:chords-compose:VERSION")

Usage

There are a few main components to using the library:

  • ChordWidget is the ChordView implementation that displays the chord.
  • ChordChart is a class that represents information about the chord chart that will be displayed.
  • Chord is a class that represents the markers on a chord that will be displayed.

Creating an instance of ChordWidget

Android:

<!-- Specify an exact size (MATCH_PARENT, MATCH_CONSTRAINTS, DP value). -->
<com.chrynan.chords.widget.ChordWidget
        android:id="@+id/chordWidget"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

Kotlin JS:

val widget = ChordWidget(htmlCanvas)

Jetpack Compose:

ChordWidget(
    modifier = Modifier.size(width = 200.dp, height = 200.dp),
    chord = chord,
    chart = chart
)

Assigning a ChordChart to a ChordWidget

chordWidget?.chart = ChordChart(
    fretStart = FretNumber(1),
    fretEnd = FretNumber(2),
    stringCount = 6,
    stringLabels = setOf(
        StringLabel(string = StringNumber(1), label = "e"),
        StringLabel(string = StringNumber(2), label = "B"),
        StringLabel(string = StringNumber(3), label = "G"),
        StringLabel(string = StringNumber(4), label = "D"),
        StringLabel(string = StringNumber(5), label = "A"),
        StringLabel(string = StringNumber(6), label = "E")
    )
)

Creating a Chord using the DSL

val chord = chord("G") {
    +ChordMarker.Note(
        fret = FretNumber(3),
        finger = Finger.MIDDLE,
        string = StringNumber(6)
    )
    +ChordMarker.Note(
        fret = FretNumber(2),
        finger = Finger.INDEX,
        string = StringNumber(5)
    )
    +ChordMarker.Open(string = StringNumber(4))
    +ChordMarker.Open(string = StringNumber(3))
    +ChordMarker.Note(
        fret = FretNumber(3),
        finger = Finger.RING,
        string = StringNumber(2)
    )
    +ChordMarker.Note(
        fret = FretNumber(3),
        finger = Finger.PINKY,
        string = StringNumber(1)
    )
}

Assigning a Chord to a ChordWidget

chordWidget?.chord = chord

Note: This library doesn't try to coerce values to fit into a chart or exclude values that exceed the chart bounds. If the ChordChart and Chord have inconsistent values, the ChordWidget may look peculiar. It's important for the user of the library to properly handle coordinating the different components.

Parsing Chords from other formats

The ChordParser interface takes in an input type and outputs a ChordParseResult. This interface can be implemented for different format input types. There are a couple provided ChordParser implementations.

AsciiChordParser:

AsciiChordParser parses a String input of an ASCII Chord Diagram and outputs a ChordParseResult containing a Chord.

val chordDiagram = """
            C
    e |-----0------|
    B |-----1------|
    G |-----0------|
    D |-----2------|
    A |-----3------|
    E |------------|
""".trimIndent()

val parser = AsciiChordParser()

launch {
    // parse() is a suspending function and needs to be called from another suspending
    // function or a coroutine
    val result = parser.parse(chordDiagram)

    val chord: Chord = result.chord
    val stringLabels: Set<StringLabel> = result.stringLabels
    val baseFret: FretNumber? = result.baseFret
}

ChordProParser:

ChordProParser parses a String input of a Chord Pro (Chord or Define) Directive and outputs a ChordParseResult containing a Chord.

val chordDiagram = "{define: Bes base-fret 1 frets 1 1 3 3 3 1 fingers 1 1 2 3 4 1}"

val parser = ChordProParser()

launch {
    // parse() is a suspending function and needs to be called from another suspending
    // function or a coroutine
    val result = parser.parse(chordDiagram)

    val chord: Chord = result.chord
    val stringLabels: Set<StringLabel> = result.stringLabels
    val baseFret: FretNumber? = result.baseFret
}

Customizing the appearance

ChordWidget implements the ChordView interface which contains properties to alter the appearance of the view.

ChordView:

interface ChordView {

    ...

    var fitToHeight: Boolean

    var showFretNumbers: Boolean

    var showFingerNumbers: Boolean

    var stringLabelState: StringLabelState

    var mutedStringText: String

    var openStringText: String

    var fretColor: ColorInt

    var fretLabelTextColor: ColorInt

    var stringColor: ColorInt

    var stringLabelTextColor: ColorInt

    var noteColor: ColorInt

    var noteLabelTextColor: ColorInt

    ...
}

Updating properties directly on ChordWidget:

chordWidget?.noteColor = Color.BLUE
chordWidget?.openStringText = "o"

Note: That in Kotlin JS, you have to explicitly call the render() function after updating properties on the ChordWidget.

Updating properties using a ViewModel and Binder:

val binder = ChordViewBinder(chordWidget)

val viewModel = ChordViewModel(
    fretColor = Color.BLACK,
    fretLabelTextColor = Color.WHITE,
    stringLabelTextColor = Color.BLACK,
    stringColor = Color.BLACK,
    noteColor = Color.BLACK,
    noteLabelTextColor = Color.WHITE
)

binder.bind(viewModel)

Note: That in Kotlin JS, there is a convenience function ChordViewBinder.bindAndRender() which will bind the properties from the ChordViewModel to the ChordWidget and call render().

Updating properties in Android XML:

<com.chrynan.chords.widget.ChordWidget
        android:id="@+id/chordWidget"
        android:layout_width="200dp"
        android:layout_height="300dp"
        app:stringLabelState="label"
        app:showFretNumbers="false"/>

Available Android XML Attributes:

<attr name="fretColor" format="color"/>
<attr name="fretLabelTextColor" format="color"/>
<attr name="stringColor" format="color"/>
<attr name="stringLabelTextColor" format="color"/>
<attr name="noteColor" format="color"/>
<attr name="noteLabelTextColor" format="color"/>
<attr name="mutedStringText" format="string"/>
<attr name="openStringText" format="string"/>
<attr name="showFingerNumbers" format="boolean"/>
<attr name="showFretNumbers" format="boolean"/>
<attr name="stringLabelState" format="enum">
<enum name="number" value="0"/>
<enum name="label" value="1"/>
<enum name="hide" value="2"/>
</attr>
<attr name="fitToHeight" format="boolean"/>
<attr name="fretLabelTypeface" format="reference"/>
<attr name="noteLabelTypeface" format="reference"/>
<attr name="stringLabelTypeface" format="reference"/>

Selectable Chord names in Text using Android Spans

The library comes with a ChordSpan which allows the pairing of text with a Chord. And when the ChordSpan is selected, a listener is alerted with the Chord.

Adding a ChordSpan to a TextView:

val text = SpannableString("G")
val span = ChordSpan(chord, this) // "this" refers to the listener

text.setSpan(span, 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)

textView?.text = text
// Need to specify LinkTouchMovementMethod as the movement method for clicks to work
textView?.movementMethod = LinkTouchMovementMethod()

Using DSL functions to add a ChordSpan to a TextView:

val textBuilder = buildSpannableString {
    +chordSpan(chord, listener)

    +chordSpan("G", chord) {
        // Handle click event
    }

    +styledChordSpan(chord, listener) {
        this.backgroundColor = Color.BLUE
    }
}

textView?.text = textBuilder
// Need to specify LinkTouchMovementMethod as the movement method for clicks to work
textView?.movementMethod = LinkTouchMovementMethod()

Listening to Chord selected events:

class MainActivity : AppCompatActivity(),
    ChordSpan.ChordSelectedListener {

    override fun onChordSpanSelected(chord: Chord) {
        // Perform action with chord
    }
}

Customizing the ChordSpan appearance:

ChordSpan extends from TouchableSpan which inherits from TouchableSpanView and has the following customizable properties:

var backgroundColor = Color.TRANSPARENT
var selectedBackgroundColor = Color.TRANSPARENT
var textColor = Color.BLUE
var selectedTextColor = Color.BLUE
var isUnderlined = false
var isUnderlinedWhenSelected = false
var textTypeface = Typeface.DEFAULT
var selectedTextTypeface = Typeface.DEFAULT

These properties can be changed on the span:

span.textColor = Color.RED

Passing Chords between Android components

The model classes are not Parcelable because they are in a Kotlin multi-platform module and don't have access to Android Framework classes. But the Android library module does have wrapper classes that handle the serialization and de-serialization of the Chord and ChordChart models.

These classes are ParcelableChordWrapper and ParcelableChartWrapper. To pass Chord and ChordChart between components, such as, in a Bundle, just wrap them with their respective wrapper models.

arguments =
    Bundle().apply {
        putParcelable(KEY_CHORD, ParcelableChordWrapper(chord))
        putParcelable(KEY_CHART, ParcelableChartWrapper(chart))
    }

Then retrieve the wrappers just as you would with any other Parcelable object.

arguments?.getParcelable<ParcelableChordWrapper>(KEY_CHORD)
arguments?.getParcelable<ParcelableChartWrapper>(KEY_CHART)

For convenience, there are extension functions on the Bundle and Intent objects which handle the wrapping and unwrapping of the Chord and ChordChart objects.

Bundle:

arguments =
    Bundle().apply {
        putChord(KEY_CHORD, chord)
        putChordChart(KEY_CHART, chart)
    }

val chord = arguments?.getChord(KEY_CHORD)
val chart = arguments?.getChordChart(KEY_CHART)

Intent:

intent.putChord(KEY_CHORD, chord)
intent.putChordChart(KEY_CHART, chart)

val chord = intent.getChordExtra(KEY_CHORD)
val chart = intent.getChordChartExtra(KEY_CHART)

There is also a convenience ChordAndChart class (with similar Parcelable extension functions) for when both a Chord and a ChordChart need to be passed between Android components together.

val chordAndChart = ChordAndChart(chord = chord, chart = chordChart)

// Bundle
arguments = bundle.putChordAndChart(KEY_CHORD_AND_CHART, chordAndChart)
arguments?.getChordAndChart(KEY_CHORD_AND_CHART)

// Intent
intent.putChordAndChartExtra(KEY_CHORD_AND_CHART, chordAndChart)
intent.getChordAndChartExtra(KEY_CHORD_AND_CHART)

Samples

Checkout the sample modules for examples on using the library.

License

Copyright 2020 chRyNaN

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].