Note
Go to the end to download the full example code.
WebApp Example
This is a basic example for creating a MusicFlower web app with a custom visualiser.
Default Version
The default version of the web app, which you can run with python -m musicflower, uses the following startup script
from musicflower.webapp import WebApp
import musicflower.features as f
import musicflower.visualisers as v
app = WebApp(verbose=True) # print additional info about registered features, callbacks etc.
f.use_chroma_features(app, n=200) # max temporal resolution of 200
v.use_fourier_visualiser(app) # register visualiser and required features
v.use_keyscape_visualiser(app) # ...
v.use_tonnetz_visualiser(app) # ...
v.use_spectral_dome_visualiser(app) # ...
app.init(figure_width=1500, figure_height=800) # larger figures
# app.run() # start up the web app (uncomment to actually run!)
registered 'chroma-features' feature extractor
registered 'fourier-features' feature remapper
registered 'Fourier Coefficients' visualiser
registered 'chroma-scape-features' feature remapper
registered 'fourier-scape-features' feature remapper
registered 'Keyscape' visualiser
registered 'Tonnetz' visualiser
registered 'Spectral Dome' visualiser
initialised 'chroma-features' feature extractor
initialised 'fourier-features' feature remapper with callbacks for 'chroma-features'
initialised 'chroma-scape-features' feature remapper with callbacks for 'chroma-features'
initialised 'fourier-scape-features' feature remapper with callbacks for 'chroma-scape-features'
initialised 'Fourier Coefficients' visualiser with callbacks for 'fourier-features'
initialised 'Keyscape' visualiser with callbacks for 'fourier-scape-features', 'chroma-scape-features'
initialised 'Tonnetz' visualiser with callbacks for 'chroma-features'
initialised 'Spectral Dome' visualiser with callbacks for 'fourier-scape-features', 'chroma-scape-features'
<musicflower.webapp.WebApp object at 0x7f4841dcc1c0>
The use_… functions are convenience functions for features and visualisers to automatically register the required dependencies. A more explicit version of the startup script would look like this
app = WebApp(verbose=True)
# define a downsampled version of chroma features using feature remappers
def chroma_features_n(*, audio, app, n=200):
cf = f.chroma_features(audio=audio, app=app, normalised=False)
cf = f.downsampler(features=[cf], app=app, n=n)
cf = f.normaliser(features=[cf], app=app)
return cf
# features
app.register_feature_extractor(name='chroma-features',
func=chroma_features_n)
app.register_feature_remapper(remapper_name='fourier-features',
feature_names=['chroma-features'],
func=f.fourier_features)
app.register_feature_remapper(remapper_name='chroma-scape-features',
feature_names=['chroma-features'],
func=f.chroma_scape_features)
app.register_feature_remapper(remapper_name='fourier-scape-features',
feature_names=['chroma-scape-features'],
func=f.fourier_features)
# visualisers
app.register_visualiser(visualiser_name='Fourier Coefficients',
feature_names=['fourier-features'],
func=v.fourier_visualiser)
app.register_visualiser(visualiser_name='Keyscape',
feature_names=['fourier-scape-features',
'chroma-scape-features'],
func=v.keyscape_visualiser)
app.register_visualiser(visualiser_name='Tonnetz',
feature_names=['chroma-features'],
func=v.tonnetz_visualiser)
app.register_visualiser(visualiser_name='Spectral Dome',
feature_names=['fourier-scape-features',
'chroma-scape-features'],
func=v.spectral_dome_visualiser)
app.init(figure_width=1500, figure_height=800)
# app.run() # uncomment to actually run
registered 'chroma-features' feature extractor
registered 'fourier-features' feature remapper
registered 'chroma-scape-features' feature remapper
registered 'fourier-scape-features' feature remapper
registered 'Fourier Coefficients' visualiser
registered 'Keyscape' visualiser
registered 'Tonnetz' visualiser
registered 'Spectral Dome' visualiser
initialised 'chroma-features' feature extractor
initialised 'fourier-features' feature remapper with callbacks for 'chroma-features'
initialised 'chroma-scape-features' feature remapper with callbacks for 'chroma-features'
initialised 'fourier-scape-features' feature remapper with callbacks for 'chroma-scape-features'
initialised 'Fourier Coefficients' visualiser with callbacks for 'fourier-features'
initialised 'Keyscape' visualiser with callbacks for 'fourier-scape-features', 'chroma-scape-features'
initialised 'Tonnetz' visualiser with callbacks for 'chroma-features'
initialised 'Spectral Dome' visualiser with callbacks for 'fourier-scape-features', 'chroma-scape-features'
<musicflower.webapp.WebApp object at 0x7f4768792770>
Custom Visualiser
Creating your own a web app with a custom visualiser is as easy as defining a single callback function
import plotly.graph_objects as go
def my_custom_visualiser(*, features, position, **kwargs):
return go.Figure(data=[go.Bar(
y=features[0][round(position * (len(features[0]) - 1))]
)])
We can now register this function as a visualiser and start up the web app with some additional parameters to facilitate debugging
from musicflower.webapp import WebApp
app = WebApp(verbose=True)
f.use_chroma_features(app)
app.register_visualiser('Chroma Bars', ['chroma-features'], my_custom_visualiser)
app.init(
# audio_file="/path/to/audio/file.mp3" # automatically pre-loading an audio file can be convenient for debugging
)
# app.run(debug=True) # run the app in debug mode to see exceptions raised in callback functions
registered 'chroma-features' feature extractor
registered 'Chroma Bars' visualiser
initialised 'chroma-features' feature extractor
initialised 'Chroma Bars' visualiser with callbacks for 'chroma-features'
<musicflower.webapp.WebApp object at 0x7f4851f14490>
A slightly more elaborate version of the visualiser could look as follows
from pitchtypes import EnharmonicPitchClass
def my_custom_visualiser(*, features, position, app=WebApp, **kwargs):
features = app.check_features(features)
position = app.position_idx(position, features=features)
data = features[position]
fig = go.Figure(data=[go.Bar(
x=[str(EnharmonicPitchClass(i)) for i in range(12)],
y=data
)])
fig.update_yaxes(range=[0, 1])
return app.update_figure_layout(fig)
app = WebApp(verbose=True)
f.use_chroma_features(app, 200)
app.register_visualiser('Chroma Bars', ['chroma-features'], my_custom_visualiser)
app.init()
# app.run(debug=True)
registered 'chroma-features' feature extractor
registered 'Chroma Bars' visualiser
initialised 'chroma-features' feature extractor
initialised 'Chroma Bars' visualiser with callbacks for 'chroma-features'
<musicflower.webapp.WebApp object at 0x7f4841dcf670>
Total running time of the script: (0 minutes 0.055 seconds)