See it in action:
https://github.com/user-attachments/assets/320e19f3-4685-462c-9de5-8c92a0aa24e1
The first screen the user sees is the Home screen. This screen handles asking for bluetooth permissions and navigating between two screens. Once permissions are granted, the user can go to either the MidiRoomScreen or the MidiUploadScreen.
The user enters this screen either by selecting "upload" in the home screen or by selecting "select file" in the MidiRoom screen.
The "select file" button opens the Android file picker, narrowed down to just .mid files.
From there, it passes the InputStream through convertMidiToSong
. This takes all Note On and Note Off events and turns each of them into an array with 3 numbers:
[tick (timestamp), pitch, velocity (volume)]
This, along with user inputted information, is stored in the SongsRepository via insertSong.
The user enters this page either after selecting "finished" in the upload screen or by selecting "Midi Room" in the home screen.
Here, all the songs stored in the local database are displayed in clickable cards. There is a search bar above the list and it narrows down song cards as the user starts typing their query.
When the user selects a song, the song ID is sent to ViewMidiScreen via the NavigationDestination.
A misnomer, this doesn't display a MIDI file but rather holds controls for streaming to the arudino. Currently, an animated countdown displays and then the song is sent via bluetooth. The play/pause buttons, along with rewind/ff, are not operational currently but will send a signal to the arduino.
This app uses Compose Navigation. Each screen has an associated NavigationDestination object, which defines the path to the screen and any additional arguments. For navigating to the ViewMidiScreen, a song ID is passed from the MidiRoomScreen via an onClick function created in the AppNavGraph and then used in the ViewMidiViewModel to retrieve the song from the app.
This app uses Room to manage a local database. It currently supports searching by song name or artist, getting all the songs, getting one song by name or id, and includes the built-in functions: insert, update, and delete. It is used in the to insert new songs into the database, and the to display all saved songs and search through the database.
This app also uses Retrofit to get album covers from and . It uses the user-inputted song name and artist name to query MusicBrainz for all associated releases, then picks one and displays the album cover.
Hilt is used to inject dependencies, and providers are defined in the AppModule.
Currently a majority of the code sits in the BLE class, and is hardcoded for a specific device, service, and characteristic (my UUIDs are set in the arduino code). For the purposes of this project, all that needs to be done is connect to the specified device and send a ByteStream and occasionally some other bytes (the behavior of play/pause is TBD). Because of this, the main BLE API is scanAndConnnectToTarget and writeCharacteristic.