roszcz's picture
Update app.py
db67129 verified
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()