Spaces:
Running
Running
import numpy as np | |
import streamlit as st | |
import streamlit_pianoroll | |
from fortepyan import MidiPiece | |
st.set_page_config( | |
page_title="PianoRoll Demo", | |
page_icon=":musical_keyboard:", | |
) | |
def main(): | |
piano_music_demo() | |
def piano_music_demo(): | |
piece = MidiPiece.from_file("haydn.mid") | |
# TODO Improve fortepyan to make this cleaner | |
piece.time_shift(-piece.df.start.min()) | |
st.write("## Display a PianoRoll player") | |
st.write(""" | |
The core functionality of pianorolls includes music playback and visualization. | |
If you have a MIDI file with piano music, see here for instructions on interacting with it using Streamlit components. | |
""") | |
code = """ | |
import streamlit_pianoroll | |
from fortepyan import MidiPiece | |
piece = MidiPiece.from_file("haydn.mid") | |
streamlit_pianoroll.from_fortepyan(piece) | |
""" | |
st.code(code, language="python") | |
streamlit_pianoroll.from_fortepyan(piece) | |
st.info( | |
body="This component is dedicated to piano music, there's no way to interract with multiple instruments.", | |
icon="🎹", | |
) | |
st.write("## Conditional coloring") | |
st.write(""" | |
To create a pianoroll with different notes in separate colors, | |
create two `MidiPiece` objects, each containing the notes for one color. | |
""") | |
st.write("#### Absolute pitch value condition") | |
st.write(""" | |
Here's how to highlight notes with pitch above or below a certain threshold. | |
Value of pitch 60 corresponds to the middle C (C4) on a piano keyboard | |
([refrence table](https://inspiredacoustics.com/en/MIDI_note_numbers_and_center_frequencies)). | |
""") | |
code = """ | |
df = piece.df | |
ids = df.pitch > pitch_threshold | |
part_a = df[ids] | |
part_b = df[~ids] | |
piece_a = MidiPiece(df=part_a) | |
piece_b = MidiPiece(df=part_b) | |
streamlit_pianoroll.from_fortepyan( | |
piece=piece_a, | |
secondary_piece=piece_b, | |
) | |
""" | |
st.code(code, language="python") | |
df = piece.df.copy() | |
pitch_threshold = st.number_input( | |
label="pitch_threshold", | |
min_value=df.pitch.min(), | |
max_value=df.pitch.max(), | |
value=60, | |
) | |
ids = df.pitch > pitch_threshold | |
part_a = df[ids].copy() | |
part_b = df[~ids].copy() | |
piece_a = MidiPiece(df=part_a) | |
piece_b = MidiPiece(df=part_b) | |
streamlit_pianoroll.from_fortepyan( | |
piece=piece_a, | |
secondary_piece=piece_b, | |
) | |
st.write("#### Note duration condition") | |
st.write(""" | |
Here's how to highlight notes based on their absolute duration, which can differentiate between fast and slow notes. | |
""") | |
code = """ | |
df = piece.df | |
ids = df.duration > duration_threshold | |
part_a = df[ids] | |
part_b = df[~ids] | |
piece_a = MidiPiece(df=part_a) | |
piece_b = MidiPiece(df=part_b) | |
streamlit_pianoroll.from_fortepyan( | |
piece=piece_a, | |
secondary_piece=piece_b, | |
) | |
""" | |
st.code(code, language="python") | |
df = piece.df.copy() | |
duration_threshold = st.number_input( | |
label="duration threshold [s]", | |
min_value=0.05, | |
max_value=5., | |
value=0.25, | |
) | |
ids = df.duration > duration_threshold | |
part_a = df[ids].copy() | |
part_b = df[~ids].copy() | |
piece_a = MidiPiece(df=part_a) | |
piece_b = MidiPiece(df=part_b) | |
streamlit_pianoroll.from_fortepyan( | |
piece=piece_a, | |
secondary_piece=piece_b, | |
) | |
st.write("#### Music generation") | |
st.write(""" | |
Here's how to show the results of a generative algorithm designed to respond to a musical input prompt. | |
We can use notes with pitches below 72 (C5) as the prompt and display them alongside the generated output. | |
This example performs a random shuffle of note pitch values, so the results are not musically appealing | |
(your algorithms should produce better results). | |
""") | |
code = """ | |
df = piece.df.copy() | |
ids = df.pitch < 72 | |
prompt_df = df[ids].copy() | |
prompt_piece = MidiPiece(df=part_a) | |
# Use your implementation here: | |
generated_df = music_generation_algorithm(prompt_df) | |
generated_piece = MidiPiece(df=generated_df) | |
streamlit_pianoroll.from_fortepyan( | |
piece=prompt_piece, | |
secondary_piece=generated_piece, | |
) | |
""" | |
st.code(code, language="python") | |
df = piece.df.copy() | |
ids = df.pitch < 72 | |
part_a = df[ids].copy() | |
piece_a = MidiPiece(df=part_a) | |
# Fake random algorithm | |
part_b = df[~ids].copy() | |
part_b.pitch = np.random.permutation(part_b.pitch) | |
part_b.velocity = np.random.permutation(part_b.velocity) | |
piece_b = MidiPiece(df=part_b) | |
streamlit_pianoroll.from_fortepyan( | |
piece=piece_a, | |
secondary_piece=piece_b, | |
) | |
if __name__ == "__main__": | |
main() | |