A story about making Hanon-like sheet music with Python

Introduction

Do you know Hanon Piano textbooks? Many people who have experience playing the piano may have unpleasant memories. The Hanon Piano Textbook is a textbook that teaches you the very basics of playing the piano. Seeing is believing, so be sure to check out Video being played and Sheet music Take a look at 11753162091.html). This time, I aimed to automatically create songs like Nos. 1 to 20 in Hanon Piano textbooks.

Language and tools used

The language used is ** Python **. I also used ** music21 **, a Python music information processing library developed at MIT. Actually, music21 itself does not create the score, but MuseScore and Lilypond do. (However, I don't actually touch MuseScore or Lilypond, so I don't need to know anything about it.) Regarding music21, I am very grateful to this blog.

What is Hanon-ish?

To make a Hanon-like score, you have to think about Hanon-like. I decided the following conditions to be Hanon-like. It may be difficult for people who are not playing music to understand, so it would be nice if you could think that you decided the rules while looking at the score yourself.

  1. The first sound is do.
  2. Repeat what you did in bar 1 in bars 2-14 (ascending). When repeating, raise one note from the previous measure.
  3. The right and left hands are unison with different octaves.
  4. The same sound is not continuous.
  5. Keep the sound of one bar within 8 degrees.
  6. Measures 15-28 go down.
  7. The first note in bar 15 begins with Seo. Make the movement contrast with the ascending.
  8. Bar 29 ends with a stretch.

Implemented to randomly create a score that meets these conditions. As a result, I got a score like this tweet!

Source code

Source code

Hanon.py


# -*- coding: utf-8 -*-
from music21 import *
import numpy
import matplotlib
import scipy
import random



#Random number generation
random_num = [-1 for _ in range(8)]
random_num[0] = 0
for i in range(1,8):
    random_num[i] = random.randint(1, 7)
    if i >= 1: #Avoid the same notes as the previous one
        while True:
            if random_num[i] != random_num[i-1]:
                break
            else:
                random_num[i] = random.randint(1, 7)



#Write the score

##Somehow the first magic
stream_right = stream.Part()
stream_left = stream.Part()

inst1 = instrument.Instrument()
inst2 = instrument.Instrument()

stream_right.append(inst1)
stream_left.append(inst2)

tc = clef.TrebleClef() #Treble clef
bc = clef.BassClef() #F clef

stream_right.append(tc)
stream_left.append(bc)

otos = ["C1", "D1", "E1", "F1", "G1", "A1", "B1", "C2", "D2", "E2", "F2", "G2", "A2", "B2", "C3", "D3", "E3", "F3", "G3", "A3", "B3", "C4", "D4", "E4", "F4", "G4", "A4", "B4", "C5", "D5", "E5", "F5", "G5", "A5", "B5", "C6"]



##right hand
for i in range(14): #Nobori
    ###1st bar
    meas = stream.Measure()
    n0 = note.Note(otos[random_num[0] + 14 + i], quarterLength = 0.25)
    meas.append(n0)
    n1 = note.Note(otos[random_num[1] + 14 + i], quarterLength = 0.25)
    meas.append(n1)
    n2 = note.Note(otos[random_num[2] + 14 + i], quarterLength = 0.25)
    meas.append(n2)
    n3 = note.Note(otos[random_num[3] + 14 + i], quarterLength = 0.25)
    meas.append(n3)
    n4 = note.Note(otos[random_num[4] + 14 + i], quarterLength = 0.25)
    meas.append(n4)
    n5 = note.Note(otos[random_num[5] + 14 + i], quarterLength = 0.25)
    meas.append(n5)
    n6 = note.Note(otos[random_num[6] + 14 + i], quarterLength = 0.25)
    meas.append(n6)
    n7 = note.Note(otos[random_num[7] + 14 + i], quarterLength = 0.25)
    meas.append(n7)
    stream_right.append(meas)
for i in range(14): #Crap
    ###1st bar
    meas = stream.Measure()
    x = 18
    n0 = note.Note(otos[x + 14 - i], quarterLength = 0.25)
    meas.append(n0)
    n1 = note.Note(otos[x - random_num[1] + 14 - i], quarterLength = 0.25)
    meas.append(n1)
    n2 = note.Note(otos[x - random_num[2] + 14 - i], quarterLength = 0.25)
    meas.append(n2)
    n3 = note.Note(otos[x - random_num[3] + 14 - i], quarterLength = 0.25)
    meas.append(n3)
    n4 = note.Note(otos[x - random_num[4] + 14 - i], quarterLength = 0.25)
    meas.append(n4)
    n5 = note.Note(otos[x - random_num[5] + 14 - i], quarterLength = 0.25)
    meas.append(n5)
    n6 = note.Note(otos[x - random_num[6] + 14 - i], quarterLength = 0.25)
    meas.append(n6)
    n7 = note.Note(otos[x - random_num[7] + 14 - i], quarterLength = 0.25)
    meas.append(n7)
    stream_right.append(meas)
###Last bar
meas = stream.Measure()
n = note.Note("C3", quarterLength = 2)
meas.append(n)
stream_right.append(meas)


##left hand
for i in range(14): #Nobori
    ###1st bar
    meas = stream.Measure()
    n0 = note.Note(otos[random_num[0] + 7 + i], quarterLength = 0.25)
    meas.append(n0)
    n1 = note.Note(otos[random_num[1] + 7 + i], quarterLength = 0.25)
    meas.append(n1)
    n2 = note.Note(otos[random_num[2] + 7 + i], quarterLength = 0.25)
    meas.append(n2)
    n3 = note.Note(otos[random_num[3] + 7 + i], quarterLength = 0.25)
    meas.append(n3)
    n4 = note.Note(otos[random_num[4] + 7 + i], quarterLength = 0.25)
    meas.append(n4)
    n5 = note.Note(otos[random_num[5] + 7 + i], quarterLength = 0.25)
    meas.append(n5)
    n6 = note.Note(otos[random_num[6] + 7 + i], quarterLength = 0.25)
    meas.append(n6)
    n7 = note.Note(otos[random_num[7] + 7 + i], quarterLength = 0.25)
    meas.append(n7)
    stream_left.append(meas)
for i in range(14): #Crap
    ###1st bar
    meas = stream.Measure()
    x = 18
    n0 = note.Note(otos[x + 7 - i], quarterLength = 0.25)
    meas.append(n0)
    n1 = note.Note(otos[x - random_num[1] + 7 - i], quarterLength = 0.25)
    meas.append(n1)
    n2 = note.Note(otos[x - random_num[2] + 7 - i], quarterLength = 0.25)
    meas.append(n2)
    n3 = note.Note(otos[x - random_num[3] + 7 - i], quarterLength = 0.25)
    meas.append(n3)
    n4 = note.Note(otos[x - random_num[4] + 7 - i], quarterLength = 0.25)
    meas.append(n4)
    n5 = note.Note(otos[x - random_num[5] + 7 - i], quarterLength = 0.25)
    meas.append(n5)
    n6 = note.Note(otos[x - random_num[6] + 7 - i], quarterLength = 0.25)
    meas.append(n6)
    n7 = note.Note(otos[x - random_num[7] + 7 - i], quarterLength = 0.25)
    meas.append(n7)
    stream_left.append(meas)
###Last bar
meas = stream.Measure()
n = note.Note("C2", quarterLength = 2)
meas.append(n)
stream_left.append(meas)


##The last magic
s = stream.Score()
s.append(stream_right)
s.append(stream_left)
s.show('musicxml')

You can also see it on GitHub. From here, I will explain the source code separately. However, I'm just starting to use music21, and I'm not sure about it, and there are many parts that imitate other people, so please point out if you make a mistake.

Libraries

python


# -*- coding: utf-8 -*-
from music21 import *
import numpy
import matplotlib
import scipy
import random

Other than random, it seems that it is necessary to use music21, so I imported it for the time being. I want to make a random number, so I will import random.

Make a random number

python


#Random number generation
random_num = [-1 for _ in range(8)]
random_num[0] = 0
for i in range(1,8):
    random_num[i] = random.randint(1, 7)
    if i >= 1: #Avoid the same notes as the previous one
        while True:
            if random_num[i] != random_num[i-1]:
                break
            else:
                random_num[i] = random.randint(1, 7)

If you randomize only the 2nd to 8th notes in the first bar, you only need to transpose it, so we prepared 7 random numbers. I wanted to make the numbers correspond to the numbers, so I made the random numbers in the range of 1-8. The while statement is turned so that the same sound does not continue.

Preparation for writing sheet music

python


##Somehow the first magic
stream_right = stream.Part()
stream_left = stream.Part()

inst1 = instrument.Instrument()
inst2 = instrument.Instrument()

stream_right.append(inst1)
stream_left.append(inst2)

tc = clef.TrebleClef() #Treble clef
bc = clef.BassClef() #F clef

stream_right.append(tc)
stream_left.append(bc)

otos = ["C1", "D1", "E1", "F1", "G1", "A1", "B1", "C2", "D2", "E2", "F2", "G2", "A2", "B2", "C3", "D3", "E3", "F3", "G3", "A3", "B3", "C4", "D4", "E4", "F4", "G4", "A4", "B4", "C5", "D5", "E5", "F5", "G5", "A5", "B5", "C6"]

First, there are two parts, right hand and left hand, so prepare two parts. Then add a treble clef and a bass clef to each part. Finally, I will prepare an array of sounds to be used from now on.

Write a score! Main part! !!

python


##right hand
for i in range(14): #Nobori
    ###1st bar
    meas = stream.Measure()
    n0 = note.Note(otos[random_num[0] + 14 + i], quarterLength = 0.25)
    meas.append(n0)
    n1 = note.Note(otos[random_num[1] + 14 + i], quarterLength = 0.25)
    meas.append(n1)
    n2 = note.Note(otos[random_num[2] + 14 + i], quarterLength = 0.25)
    meas.append(n2)
    n3 = note.Note(otos[random_num[3] + 14 + i], quarterLength = 0.25)
    meas.append(n3)
    n4 = note.Note(otos[random_num[4] + 14 + i], quarterLength = 0.25)
    meas.append(n4)
    n5 = note.Note(otos[random_num[5] + 14 + i], quarterLength = 0.25)
    meas.append(n5)
    n6 = note.Note(otos[random_num[6] + 14 + i], quarterLength = 0.25)
    meas.append(n6)
    n7 = note.Note(otos[random_num[7] + 14 + i], quarterLength = 0.25)
    meas.append(n7)
    stream_right.append(meas)
for i in range(14): #Crap
    ###1st bar
    meas = stream.Measure()
    x = 18
    n0 = note.Note(otos[x + 14 - i], quarterLength = 0.25)
    meas.append(n0)
    n1 = note.Note(otos[x - random_num[1] + 14 - i], quarterLength = 0.25)
    meas.append(n1)
    n2 = note.Note(otos[x - random_num[2] + 14 - i], quarterLength = 0.25)
    meas.append(n2)
    n3 = note.Note(otos[x - random_num[3] + 14 - i], quarterLength = 0.25)
    meas.append(n3)
    n4 = note.Note(otos[x - random_num[4] + 14 - i], quarterLength = 0.25)
    meas.append(n4)
    n5 = note.Note(otos[x - random_num[5] + 14 - i], quarterLength = 0.25)
    meas.append(n5)
    n6 = note.Note(otos[x - random_num[6] + 14 - i], quarterLength = 0.25)
    meas.append(n6)
    n7 = note.Note(otos[x - random_num[7] + 14 - i], quarterLength = 0.25)
    meas.append(n7)
    stream_right.append(meas)
###Last bar
meas = stream.Measure()
n = note.Note("C3", quarterLength = 2)
meas.append(n)
stream_right.append(meas)

First, create the first bar. At this time, when I used the for statement, for some reason there was only one sound in one bar, so I had no choice but to write it solidly. Write it as note.Note (pitch, length). The length of a note is expressed as a fraction or a decimal, with a quarter note as 1. When the first measure is completed, repeat it 14 times while transposing it to complete the ascending! Write the lower line in the same way. And don't forget to add the extension of the last bar, and you're done! !! The left hand is only an octave lower, so I omitted it.

Display with MuseScore

python


##The last magic
s = stream.Score()
s.append(stream_right)
s.append(stream_left)
s.show('musicxml')

Finally, display what you have written so far in MuseScore. You can also display it in Lilypond by rewriting the last line.

Finally

I was told that I should try machine learning in order to pursue more Hanon-likeness, so I have a desire to try it (I don't know anything, so I have to study from 0 ... ). I also want to be able to adjust the difficulty level in about 5 steps. Also, music21 seems to be able to be used for music analysis, and it seems that it can check what key it is (amazing), so I thought that I would like to play with that as well.

Recommended Posts

A story about making Hanon-like sheet music with Python
A story about an amateur making a breakout with python (kivy) ②
A story about an amateur making a breakout with python (kivy) ①
A story about trying a (Golang +) Python monorepo with Bazel
A story about making a tanka by chance with Sudachi Py
A story about a python beginner stuck with No module named'http.server'
A story about adding a REST API to a daemon made with Python
A story about machine learning with Kyasuket
The story of making a standard driver for db with python.
A story about developing a soft type with Firestore + Python + OpenAPI + Typescript
A story about Python pop and append
The story of making a module that skips mail with python
The story of making a university 100 yen breakfast LINE bot with Python
A story about a beginner making a VTuber notification bot from scratch in Python
[Python3] A story stuck with time zone conversion
A story stuck with handling Python binary data
A story about implementing a login screen with django
A story about running Python on PHP on Heroku
A story about modifying Python and adding functions
Automatic Zakuzaku, Bitcoin. A story about a Python beginner making a coin check 1-minute chart
A story about making an x86 bootloader that can boot vmlinux with Rust
A story about predicting exchange rates with Deep Learning
The story of making a music generation neural network
A story about how theano was moved with TSUBAME 2.0
A memo about building a Django (Python) application with Docker
A story about how Windows 10 users created an environment to use OpenCV3 with Python 3.5
Stumble story with Python array
A memorandum about correlation [Python]
[Python] A story about making a LINE Bot with a practical manned function on its own without using Salesforce [Messaging API]
Make a fortune with Python
A memorandum about Python mock
Automate sushi making with Python
Create a directory with python
A note about [python] __debug__
A note about hitting the Facebook API with the Python SDK
A story about how to specify a relative path in python.
A story about competing with a friend in Othello AI Preparation
A story about how to deal with the CORS problem
[Python] The first step to making a game with Pyxel
A story about trying to implement a private variable in Python.
The story of making a question box bot with discord.py
A story about building a PyPI cache server (with Docker) and making me a little happy again
[Note] A story about trying to override a class method with two underscores in Python 3 series.
Machine learning A story about people who are not familiar with GBDT using GBDT in Python
[Python, Selenium, PhantomJS] A story when scraping a website with lazy load
[Python] What is a with statement?
Solve ABC163 A ~ C with Python
Operate a receipt printer with python
A python graphing manual with Matplotlib.
Let's make a GUI with python.
Python: A Note About Classes 1 "Abstract"
Solve ABC166 A ~ D with Python
Make a simple OMR (mark sheet reader) with Python and OpenCV
Building a virtual environment with Python 3
Solve ABC168 A ~ C with Python
Make a recommender system with python
[Small story] Get timestamp with Python
A story about trying to run multiple python versions (Mac edition)
[Python] Generate a password with Slackbot
Solve ABC162 A ~ C with Python
Solve ABC167 A ~ C with Python