3.06 Meteorological Harmony Change
==================================
- With the introduction of **harm\_change** the harmony pattern can be
changed by the meteorological data. The two pattern are still defined
by hand, but when the pattern are switched, is controlled by the
weather measurements. The pattern are only changed once.
- Weather Period from 1.8.2019 to 28.8.2019
.. code:: python3
from pyknon.genmidi import Midi
from pyknon.music import Rest, Note, NoteSeq
from music_generation import*
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as plticker
from datetime import date
Read Meteorological Data
~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: python3
def read_meteo_data(fName):
colNames = ['Stao','time', 'T_Boden_20cm', 'Flash_30km', 'Glob_rad', 'QFE','T_2m','Rain_Sum','H_rel','visibi','V_wind','direction_wind']
df = pd.read_csv(fName,sep=';', skiprows=3, names=colNames, na_values='-')
print(df.head())
return df
fPath = '/mnt/daten/04_Schule/42_Kanti/Matrua/Music_generation/Organisation/MeteoSchweiz/Daten/'
fName = 'order_75330_data.txt'
dM = read_meteo_data(fPath+fName)
NT, MP = dM.shape
.. parsed-literal::
Stao time T_Boden_20cm Flash_30km Glob_rad QFE T_2m \
0 KLO 201908010000 21.5 0 2 969.5 15.3
1 KLO 201908010010 21.5 0 2 969.5 14.9
2 KLO 201908010020 21.5 0 2 969.5 14.6
3 KLO 201908010030 21.5 0 2 969.5 14.6
4 KLO 201908010040 21.4 0 2 969.6 13.7
Rain_Sum H_rel visibi V_wind direction_wind
0 0.0 80.4 20000.0 0.9 117
1 0.0 82.4 20000.0 1.1 98
2 0.0 83.7 20000.0 1.0 121
3 0.0 82.7 20000.0 1.2 119
4 0.0 88.8 20000.0 1.0 173
Chords and scales
~~~~~~~~~~~~~~~~~
.. code:: python3
C = np.array([ 0, 4, 7])
Cm = np.array([ 0, 3, 7])
Cdim = np.array([ 0, 3, 6])
CM7 = np.array([ 0, 4, 7, 11])
C7 = np.array([ 0, 4, 7, 10])
Cm7 = np.array([ 0, 3, 7, 10])
Cdim7 = np.array([ 0, 3, 6, 10])
Cdim6 = np.array([ 0, 3, 6, 9 ])
C6 = np.array([ 0, 4, 7, 9 ]) # inversion of Am7
Cm6 = np.array([ 0, 3, 7, 9 ])
Csus4 = np.array([ 0, 5, 7])
Csus2 = np.array([ 0, 2, 7])
Csus47= np.array([ 0, 5, 7, 10])
P = np.array([ 0,7]) # Power chord (Perfect unison, Perfect fifth)
B = np.array([ 0]) # Bass (Perfect unison)
major = np.array([ 0, 2, 4, 5, 7, 9, 11])
minor = np.array([ 0, 2, 3, 5, 7, 8, 10])
blues = np.array([ 0, 3, 5, 6, 7, 10])
Harmony Change
~~~~~~~~~~~~~~
The **Harm\_Change** function replaces the **pattern\_gen** function.
Harm\_Change calls the pattern\_gen function for creating the pattern.
It assembles two pattern dependent on meteorological data input. When
the data reaches a manually defined value the first time, the pattern is
changed. The Pattern changes only once. The end scale functionalities
are still in use. When a harmony change by meteorological data is not
desired, the pattern\_gen function is also available for further use.
.. code:: python3
def harm_change(meteo,value,scale1,scale2,end_scale,melody_len,mpb):
met_resolution = 10
end_zero = [[0,'C',B]] # Fake end for pattern1
i_when = (np.argwhere(meteo>=value))[0,0] # Find where value is reached first time
b_when = i_when*met_resolution/mpb # calculate in to beat_nr
if b_when >= melody_len: # when Change is out of song length
print('No pattern Change')
pattern_add = pattern_gen(scale1, end_scale, melody_len)
else:
pattern1 = pattern_gen(scale1, end_zero, b_when) # pattern_gen 1
pattern2 = pattern_gen(scale2, end_scale, melody_len - b_when) # pattern_gen 2
pattern2[:,0] = pattern2[:,0] + b_when # add b_when to the change times of second pattern
pattern_add = np.concatenate((pattern1,pattern2),axis=0) # merge both patterns
return pattern_add
tune 306\_A
-----------
- period from 11.8 to 15.8.2019
- Temperature and pressure played is played by Heckelphone and
Clarinet.
- Timpani volume is regulated by the rain.
- A music box plays the melody of the global radiation. During night
the melody is paused.
- The numbers of flashes changes the chord pattern. The first time when
15 flashes per ten minutes are reached the scale is switched from
major to minor. It would be possible to change a harmony pattern and
not only two scales.
.. code:: python3
def tune_306_A():
tune_name = 'tune_306_A'
np.random.seed(54) #50
bar, bpb = 23, 4 # bar: Takt , bpb: beat per bar
s_day, s_hour = 2, 12 # Start point in the data
mpb = 80 # minutes per beat
end_dur = 1
melody_len, start = print_dur(bar,bpb,mpb,s_day,s_hour,tune_name)
trans = met_transform(dM,[1,1,0.025,3,1.3,400,0.2,1,4.5,1,],[6,6,6,6,6,12,6,6,6,2],start)
scale1 = [[8,'C',major]]
scale2 = [[8,'C',minor]]
end_scale = [[0.5,'C',Cm]]
# Flash for changing Chord pattern
pattern = harm_change(trans[1],15,scale1,scale2,end_scale, melody_len,mpb)
# Pressure
rythem1, notenr_1 = ran_duration([1/32,1/8, 1/4,1/2], [0,2,3,1], melody_len, end_dur)
melody1 = meteo_melody(trans[3],pattern, 72, notenr_1, rythem1,mpb)
volumes1 = ran_volume([0,115], [1,8], notenr_1 )
notes1 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody1,rythem1,volumes1)] )
# temp
rythem2, notenr_2 = ran_duration([1/16,1/8, 1/4,1/2], [0,2,3,2], melody_len, end_dur)
melody2 = meteo_melody(trans[4],pattern, 60, notenr_2, rythem2,mpb)
volumes2 = ran_volume([0,115], [1,8], notenr_2 )
notes2 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody2,rythem2,volumes2)] )
#timpani rain
melody3, rythem3, volumes3 = drum([1/16], [60,63],[100,127],melody_len)
volumes3 = met_vol(trans[5],0,127,rythem3, mpb)
notes3 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody3,rythem3,volumes3)] )
# glob radation
rythem4, notenr_4 = ran_duration([1/32,1/16,1/8, 1/4,], [0,3,1,0], melody_len, end_dur)
melody4 = meteo_melody(trans[2],pattern, 85, notenr_4, rythem4, mpb)
volumes4 = ran_volume([0,110], [0,8], notenr_4 )
volumes4 = on_off(trans[2],[5,20000],volumes4, rythem4, mpb)
notes4 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody4,rythem4,volumes4)] )
instruments = [68,71,47,10]
notes = [notes1,notes2,notes3,notes4]
return notes, instruments,tune_name
.. raw:: html
tune_306_A
tune_306_A
**Instruments:** Available are at lest the 128 General-Midi (GM)
Instruments. Depending on the sound-fonts there is a bigger choice. A
list of the GM instruments can be found here.
https://jazz-soft.net/demo/GeneralMidi.html
Generate Midi and Audio file
----------------------------
.. code:: python3
def gen_midi():
# squezze into a MIDI framework
notes, instruments, tune_name = tune_306_A() # <--- select a tune <<-- <<<<<<<<<--- select a tune -----
nTracks = len(notes)
m = Midi(number_tracks=nTracks, tempo=120, instrument=instruments)
for iTrack in range(nTracks):
m.seq_notes(notes[iTrack], track=iTrack)
#--- write the MIDI file -----
midi_file_name = tune_name +'.mid' # set the name of the file
m.write(midi_file_name)
return midi_file_name
.. code:: python3
######--- Main ---######
midi_file_name = gen_midi()
midi_play(midi_file_name)
midi_audio(midi_file_name)
midi_png(midi_file_name)
.. parsed-literal::
tune_306_A: Start: 2 day 12 h End: 7.0 day 14.666666666666686 h
.. image:: output_14_1.png
External **Music\_Generation** library
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This library changes from version to version. New or changed code is
first explained above. This is a copy of music\_generation.py
.. literalinclude:: music_generation.py
:language: python