2.09 Some Examples

Four Examples with different manually defined chord patterns.

Functions which are no longer part of this development step are exported to the music_generation.py file. The file is found at the end of the page.

from pyknon.genmidi import Midi
from pyknon.music import Rest, Note, NoteSeq
from music_generation import *
import numpy as np
import matplotlib.pyplot as plt
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])
C7 = np.array([ 0, 4, 7, 10])
CM7 = np.array([ 0, 4, 7, 11])
Cm7 = np.array([ 0, 3, 7, 10])
Cm  = np.array([ 0, 3, 7])
Cdim   = np.array([ 0, 3, 6])
C   = np.array([ 0, 4, 7])
power = np.array([ 0,7])
B = np.array([ 0])

tune_2.09_A

  • Chords: C Am Dm G
  • Strings playing chords
  • Organ for the base
  • Clarinet playing major scale
def tune_209_A():
    tune_name = 'tune_209_A'
    np.random.seed(154)
    bar, bpb = 13, 4  # bar: Takt , bpb: beat per bar
    melody_len = bar * bpb

    #scales = [[1,CM7],[1,Cm7+9],[1,Cm7+2],[1,C7+7]] #rythem Change
    #scales = [[4,C7],[2,C7+5],[2,C7],[1,C7+7],[1,C7+5],[2,C7]] # Blues
    #scales = [[1,C7],[1,C7+5],[2,C7],[2,C7+5],[2,C7],[1,C7+7],[1,C7+5],[1,C7],[1,C7+7]] # Blues erweitert
    scales = [[1,C],[1,Cm+9],[1,Cm+2],[1,C+7]] #  I VI II V
    end_scale = [[1,C7+7],[1,C]]
    pattern = pattern_gen(scales, end_scale, melody_len)

    pattern2 = pattern_gen([[12,major]], end_scale, melody_len)


    # Solo voice
    range_1 = liniar_range(49,67,80,84)
    rythem1, notenr_1 = ran_duration([1/16,1/8, 1/4,1/2], [0,3,3,1], melody_len)
    melody1 = acceptance_melody([-3,-2,-1, 0, 1, 2, 3],[1,2, 2, 1, 2, 2,1],pattern2, 70, range_1, notenr_1, rythem1)
    volumes1 = ran_volume([0,100], [1,6], notenr_1 )
    notes1 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody1,rythem1,volumes1)] )

    # Bass voice
    range_2 = liniar_range(30,37,48,67)
    rythem2, notenr_2 = ran_duration([1/8, 1/4,1/2], [0,2,1], melody_len)
    melody2 = acceptance_melody([-2,-1, 0, 1, 2],[0, 3, 1, 3, 0],pattern, 40, range_2, notenr_2,rythem2)
    volumes2 = ran_volume([0,110], [0,8], notenr_2 )
    notes2 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody2,rythem2,volumes2)] )

    # Chord Voices
    range_3 = liniar_range(40,48,60,67)
    rythem3, notenr_3 = ran_duration([1/8, 1/4,1/2], [1,3,2], melody_len)
    melody3 = acceptance_melody([-2,-1, 0, 1, 2],[0, 3, 1, 3, 0],pattern, 48, range_3, notenr_3,rythem3)
    volumes3 = ran_volume([0,80], [0,8], notenr_3 )
    notes3 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody3,rythem3,volumes3)] )

    range_4 = liniar_range(40,48,60,67)
    rythem4, notenr_4 = ran_duration([1/8, 1/4,1/2], [1,3,2], melody_len)
    melody4 = acceptance_melody([-2,-1, 0, 1, 2],[0, 3, 1, 3, 0],pattern, 60, range_4, notenr_4,rythem4)
    volumes4 = ran_volume([0,80], [0,8], notenr_4 )
    notes4 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody4,rythem4,volumes4)] )

    range_5 = liniar_range(40,48,60,67)
    rythem5, notenr_5 = ran_duration([1/8, 1/4,1/2], [1,3,2], melody_len)
    melody5 = acceptance_melody([-2,-1, 0, 1, 2],[0, 3, 1, 3, 0],pattern, 54, range_5, notenr_5,rythem5)
    volumes5 = ran_volume([0,80], [0,8], notenr_5 )
    notes5= NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody5,rythem5,volumes5)] )


    plot_range([range_1,range_2,range_3],['range_1','range_2','range_3'],tune_name)
    instruments = [69,16,48,48,48]
    notes = [notes1,notes2,notes3,notes4,notes5]
    return notes, instruments,tune_name

tune__209_A
tune_209_A


tune_2.09_B

  • Chords: Cm A Dm G7
  • String quartet
def tune_209_B():
    tune_name = 'tune_209_B'
    np.random.seed(87)    # 154, 128 87
    bar, bpb = 13, 4  # bar: Takt , bpb: beat per bar
    melody_len = bar * bpb
# blues
    #scales = [[4,C7],[2,C7+5],[2,C7],[1,C7+7],[1,C7+5],[2,C7]] # Blues
    #scales = [[1,C7],[1,C7+5],[2,C7],[2,C7+5],[2,C7],[1,C7+7],[1,C7+5],[1,C7],[1,C7+7]] # Blues erweitert

    #scales = [[1,CM7],[1,Cm7+9],[1,Cm7+2],[1,C7+7]] #  I VI II V  with 7
    #scales = [[1,C],[1,Cm+9],[1,Cm+2],[1,C+7]]      #  I VI II V  major
    scales = [[1,Cm],[1,C+8],[1,Cdim+2],[1,C7+7]] #  i VI ii V  minor
    #scales = [[1,Cm],[1,C+8],[1,C+3],[1,C+10]] #  i VI III VII  minor
    end_scale = [[1,C7+7],[1,Cm]]

    pattern = pattern_gen(scales, end_scale, melody_len)

    # Violin
    range_1 = liniar_range(55,69,84,91)
    rythem1, notenr_1 = ran_duration([1/16,1/8, 1/4,1/2], [0,3,2,1], melody_len)
    melody1 = acceptance_melody([-3,-2,-1, 0, 1, 2, 3],[1,2, 2, 1, 2, 2,1],pattern, 70, range_1, notenr_1, rythem1)
    volumes1 = ran_volume([0,120], [1,6], notenr_1 )
    notes1 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody1,rythem1,volumes1)] )

    # Viola
    range_2 = liniar_range(48,62,76,85)
    rythem2, notenr_2 = ran_duration([1/8, 1/4,1/2], [1,2,1], melody_len)
    melody2 = acceptance_melody([-2,-1, 0, 1, 2],[0, 3, 1, 3, 0],pattern, 70, range_2, notenr_2,rythem2)
    volumes2 = ran_volume([0,120], [1,7], notenr_2 )
    notes2 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody2,rythem2,volumes2)] )

    # Cello
    range_3 = liniar_range(36,48,63,69)
    rythem3, notenr_3 = ran_duration([1/8, 1/4,1/2], [1,3,1], melody_len)
    melody3 = acceptance_melody([-2,-1, 0, 1, 2],[0, 3, 1, 3, 0],pattern, 58, range_3, notenr_3,rythem3)
    volumes3 = ran_volume([0,120], [1,8], notenr_3 )
    notes3 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody3,rythem3,volumes3)] )

    # Contrabass
    range_4 = liniar_range(28,36,48,55)
    rythem4, notenr_4 = ran_duration([1/8, 1/4,1/2], [1,3,2], melody_len)
    melody4 = acceptance_melody([-2,-1, 0, 1, 2],[0, 3, 1, 3, 0],pattern, 44, range_4, notenr_4,rythem4)
    volumes4 = ran_volume([0,120], [1,8], notenr_4 )
    notes4 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody4,rythem4,volumes4)] )


    plot_range([range_1,range_2,range_3,range_4],['range_1','range_2','range_3','range_4'],tune_name)
    instruments = [40,41,42,43]
    notes = [notes1,notes2,notes3,notes4]
    return notes, instruments,tune_name

tune__209_B
tune_209_B


tune_2.09_C

  • Chords: Cm Fm Bb Eb Cm Fm G7
  • Two Pianos playing chords
  • Organ for the base
  • Trumpet playing minor scale
def tune_209_C():
    tune_name = 'tune_209_C'
    np.random.seed(36)    #
    bar, bpb = 16, 4  # bar: Takt , bpb: beat per bar
    melody_len = bar * bpb

# blues
    #scales = [[4,C7],[2,C7+5],[2,C7],[1,C7+7],[1,C7+5],[2,C7]] # Blues
    #scales = [[1,C7],[1,C7+5],[2,C7],[2,C7+5],[2,C7],[1,C7+7],[1,C7+5],[1,C7],[1,C7+7]] # Blues erweitert

    #scales = [[1,CM7],[1,Cm7+9],[1,Cm7+2],[1,C7+7]] #  I VI II V  with 7
    #scales = [[1,C],[1,Cm+9],[1,Cm+2],[1,C+7]]      #  I VI II V  major
    #scales = [[1,Cm],[1,C+8],[1,Cdim+2],[1,C7+7]] #  i VI ii V  minor
    #scales = [[1,Cm],[1,C+8],[1,C+3],[1,C+10]] #  i VI III VII  minor

    scales = [[1,Cm],[1,Cm+5],[1,C+10],[1,C+3],[1,Cm],[1,Cm+5],[1,C7+7]]  #Cm Fm Bb Eb Cm Fm G7
    end_scale = [[1,Cm],[1,power]]

    pattern = pattern_gen(scales, end_scale, melody_len)
    pattern2 = pattern_gen([[12,minor]], end_scale, melody_len) # for solo voice

    # Solo voice
    range_1 = liniar_range(49,67,80,84)
    rythem1, notenr_1 = ran_duration([1/16,1/8, 1/4,1/2], [1,3,2,0], melody_len)
    melody1 = acceptance_melody([-3,-2,-1, 0, 1, 2, 3],[2,2, 2, 1, 2, 2,2],pattern2, 67, range_1, notenr_1, rythem1)
    volumes1 = ran_volume([0,80], [1,6], notenr_1 )
    notes1 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody1,rythem1,volumes1)] )

    # Bass voice
    range_2 = liniar_range(32,40,52,63)
    rythem2, notenr_2 = ran_duration([1/8, 1/4,1/2], [0,2,0], melody_len)
    melody2 = acceptance_melody([-2,-1, 0, 1, 2],[0, 3, 1, 3, 0],pattern, 44, range_2, notenr_2,rythem2)
    volumes2 = ran_volume([0,100], [0,8], notenr_2 )
    notes2 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody2,rythem2,volumes2)] )

    # Chord Voices
    range_3 = liniar_range(40,48,67,72)
    rythem3, notenr_3 = ran_duration([1/8, 1/4,1/2], [3,3,1], melody_len)
    melody3 = acceptance_melody([-2,-1, 0, 1, 2],[0, 3, 1, 3, 0],pattern, 53, range_3, notenr_3,rythem3)
    volumes3 = ran_volume([0,100], [1,8], notenr_3 )
    notes3 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody3,rythem3,volumes3)] )

    range_4 = liniar_range(40,48,67,72)
    rythem4, notenr_4 = ran_duration([1/8, 1/4,1/2], [3,3,1], melody_len)
    melody4 = acceptance_melody([-2,-1, 0, 1, 2],[0, 3, 1, 3, 0],pattern, 65, range_4, notenr_4,rythem4)
    volumes4 = ran_volume([0,100], [1,8], notenr_4 )
    notes4 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody4,rythem4,volumes4)] )


    plot_range([range_1,range_2,range_3],['range_1','range_2','range_3'],tune_name)
    instruments = [56,20,0,0]
    notes = [notes1,notes2,notes3,notes4]
    return notes, instruments,tune_name

tune__209_C
tune_209_C


tune_2.09_D

  • Chords: Cm Cm7/Bb Eb Ab7 G7 | C C/E F F#dim Ab7 G7 Cm
  • Three guitars playing chords
  • an acoustic bass
  • Organ for the base with separate bass pattern. Mostly the root note.
  • Vibraphone as solo voice
def tune_209_D():
    tune_name = 'tune_209_D'
    np.random.seed(144    )    #  79 33
    bar, bpb = 17, 4  # bar: Takt , bpb: beat per bar
    melody_len = bar * bpb

# blues
    #scales = [[4,C7],[2,C7+5],[2,C7],[1,C7+7],[1,C7+5],[2,C7]] # Blues
    #scales = [[1,C7],[1,C7+5],[2,C7],[2,C7+5],[2,C7],[1,C7+7],[1,C7+5],[1,C7],[1,C7+7]] # Blues erweitert

    #scales = [[1,CM7],[1,Cm7+9],[1,Cm7+2],[1,C7+7]] #  I VI II V  with 7
    #scales = [[1,C],[1,Cm+9],[1,Cm+2],[1,C+7]]      #  I VI II V  major
    #scales = [[1,Cm],[1,C+8],[1,Cdim+2],[1,C7+7]] #  i VI ii V  minor
    #scales = [[1,Cm],[1,C+8],[1,C+3],[1,C+10]] #  i VI III VII  minor
    #scales = [[1,Cm],[1,Cm+5],[1,C+10],[1,C+3],[1,Cm],[1,Cm+5],[1,C7+7]]  # Cm Fm Bb Eb Cm Fm G7

 # | Cm Cm7/Bb Eb Ab7 G7 | C C/E F F#dim Ab7 G7 Cm |
    scales =[[1,Cm],[1,Cm7],[1,C+3],[1,C7+8],[1,C7+7],[1,C],[1,C],[1,Cdim+6],[1,C7+8],[1,C7+7],[1,Cm]]
    bass1 =  [[1,B],[1,B+10],[1,B+3],[1,B+8],[1,B+7],[1,B],[1,B+4],[1,B+6],[1,B+8],[1,B+7],[1,B]]

    end_scale = [[0.5,Cm],[0.5,power]]
    #end_scale = [[0,power]]

    pattern = pattern_gen(scales, end_scale, melody_len)
    bass1 = pattern_gen(bass1, end_scale, melody_len)
    #pattern2 = pattern_gen([[12,minor]], end_scale, melody_len)

    # Solo voice
    range_1 = liniar_range(50,60,80,88)
    rythem1, notenr_1 = ran_duration([1/16,1/8, 1/4,1/2], [2,5,3,0.5], melody_len)
    melody1 = acceptance_melody([-2,-1, 0, 1, 2],[1, 3, 1, 3, 1],pattern, 70, range_1, notenr_1, rythem1)
    volumes1 = ran_volume([0,127], [1,4], notenr_1 )
    notes1 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody1,rythem1,volumes1)] )

    # Bass1  Accustic
    range_2 = liniar_range(38,41,52,67)
    rythem2, notenr_2 = ran_duration([1/8, 1/4,1/2], [4,4,1], melody_len)
    melody2 = acceptance_melody([-2,-1, 0, 1, 2],[0, 3, 1, 3, 0],pattern, 50, range_2, notenr_2,rythem2)
    volumes2 = ran_volume([0,60], [0,8], notenr_2 )
    notes2 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody2,rythem2,volumes2)] )

    # Bass2  Organ
    range_6 = liniar_range(30,38,50,62)
    rythem6, notenr_6 = ran_duration([1/8, 1/4,1/2], [0,1,1], melody_len)
    melody6 = acceptance_melody([-2,-1, 0, 1, 2],[1, 1, 1, 1, 1],bass1, 48, range_6, notenr_6,rythem6)
    volumes6 = ran_volume([0,110], [0,8], notenr_6 )
    notes6 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody6,rythem6,volumes6)] )

    # Chord Voices
    range_3 = liniar_range(40,50,67,72)
    rythem3, notenr_3 = ran_duration([1/8, 1/4,1/2], [1,2,1], melody_len)
    melody3 = acceptance_melody([-2,-1, 0, 1, 2],[0, 3, 1, 3, 0],pattern, 65, range_3, notenr_3,rythem3)
    volumes3 = ran_volume([0,80], [0,8], notenr_3 )
    notes3 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody3,rythem3,volumes3)] )

    range_4 = liniar_range(40,50,67,72)
    rythem4, notenr_4 = ran_duration([1/8, 1/4,1/2], [1,2,1], melody_len)
    melody4 = acceptance_melody([-2,-1, 0, 1, 2],[0, 3, 1, 3, 0],pattern, 60, range_4, notenr_4,rythem4)
    volumes4 = ran_volume([0,90], [0,8], notenr_4 )
    notes4 = NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody4,rythem4,volumes4)] )

    range_5 = liniar_range(40,50,67,72)
    rythem5, notenr_5 = ran_duration([1/8, 1/4,1/2], [1,2,1], melody_len)
    melody5 = acceptance_melody([-2,-1, 0, 1, 2],[0, 3, 1, 3, 0],pattern, 54, range_5, notenr_5,rythem5)
    volumes5 = ran_volume([0,90], [0,8], notenr_5 )
    notes5= NoteSeq( [Note(no,octave=0, dur=du, volume=vo) for no,du,vo in zip(melody5,rythem5,volumes5)] )


    plot_range([range_1,range_2,range_3],['range_1','range_2','range_3'],tune_name)
    instruments = [11,32,24,24,24,16]
    notes = [notes1,notes2,notes3,notes4,notes5,notes6]
    return notes, instruments,tune_name

tune__209_D
tune_209_D


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

def gen_midi():
#     squezze into a MIDI framework
    notes, instruments, tune_name = tune_209_C() #  <--- 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
######---  Main  ---######
midi_file_name = gen_midi()

#midi_play(midi_file_name)
midi_audio(midi_file_name)
midi_png(midi_file_name)
../../_images/output_17_0.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

from pyknon.genmidi import Midi
from pyknon.music import Rest, Note, NoteSeq
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as plticker
from datetime import date


# [[[[[[[[[[[[[[[[[[[   -- Functions for Music Generation --    ]]]]]]]]]]]]]]]]]]]

def scale_create(tones):
    tones = np.asarray(tones)   # tones which form chord or scale in the first octave (0-11)
    if any(tones > 11):             # tones over one octave?
        tones = np.mod(tones,12)    # set the thones in one octave
        tones = np.sort(tones)      # sort the tones new
        tones = np.unique(tones)    # remove duplicate tones
    octave = np.repeat( np.linspace(0,108, num=10), len(tones))
    scale = np.add( octave, np.tile(tones, 10)) # add element wise octave and note
    return scale.astype(int)
    
def fade(start,end,steps): 
    fade = np.around( np.linspace(start,end,num=steps))
    fade = fade.astype(int)
    return fade

def ran_volume(volume, prob_volume, melody_len):
    volume = np.asarray(volume, dtype=int)         # this are the allowed volumes of thenotes
    prob_volume = np.asarray(prob_volume)          # this are the probabilities how often each volume will occure
    prob_volume = prob_volume/np.sum(prob_volume) 
    volumes = np.r_[np.random.choice(volume, size=melody_len, p=prob_volume)]
    return volumes

#   liniar_range: Generates an range in which the instrument can play. 
def liniar_range(r_start, r_top, r_edge, r_end): # acceptance range of the instrument 
    h = 100 # hight of acceptance function
    a_range = np.zeros(121, dtype=int)  # only to midi =120 as 127 is not a complete octave
    np.put(a_range, range(r_start,r_top),  np.linspace(0,h, num=(r_top -r_start)) )
    np.put(a_range, range(r_top, r_edge),  np.linspace(h,h, num=(r_edge-r_top  )) )
    np.put(a_range, range(r_edge, r_end),  np.linspace(h,0, num=(r_end -r_edge )) )
    return a_range
    
#   i_last_note: finds de i value of the last not in the actual scale.
def i_last_note(note, scale):
    i_note = (np.abs(scale - note)).argmin()
    return i_note

#   intvl_next is a modification of intvl_melody. But it does only creats one interval and not an array/melody in one time.
def intvl_next(intvl, prob_intvl):  #singel interval
    intvl = np.asarray(intvl)            # Possible interval
    prob_intvl = np.asarray(prob_intvl)         # Probability of each interval
    prob_intvl = prob_intvl/np.sum(prob_intvl)
    interval = np.random.choice(intvl, size=1, p=prob_intvl)
    return interval[0]

#   acceptance: accepts and refuses proposed nots with Metropolis-Hasting Algorythem.
#     x is the value in the aceptance range of the current note, while x_new is it from the proposoal note
def acceptance(x, x_new):
    if x_new < 1:
        if x < 1: print('start_note not in range') ; x = start_note_not_in_range
    quot = x_new/x
    if quot >= 1: return True
    if np.random.uniform(0,1)< quot: return True
    else: return False
    
def ran_duration(duration, prob_duration, melody_len):    
    duration= np.asarray(duration)                  # this are the allowed durations of the notes
    prob_duration = np.asarray(prob_duration)       # this are the probabilities how often each will occure
    prob_duration = prob_duration/np.sum(prob_duration)
    cumsum, melody_len, rythem = 0, melody_len/4 , np.asarray([])  #melody_len/4 as note values are quarter
    while cumsum < melody_len:
        note_len = np.random.choice(duration, p=prob_duration)
        cumsum = cumsum + note_len
        rythem = np.append(rythem,note_len)
    return rythem , len(rythem)

#   pattern_gen takes the chord pattern (scales): it reapeats the pattern as long the melody is, and generates the beat number where the chords change. 
# it also adds the end pattern
def pattern_gen(scales,end_scale, melody_len):
    bpb = 4  # beats per bar
    
#--scales
    scales   = np.asarray(scales)
    factor = int(np.trunc(melody_len/(np.sum(scales[:,0]) * bpb)) + 1) # factor rounded up: how many times is the pattern used
    change_times = np.cumsum(np.tile(scales[:,0],factor)) * bpb        # create change time list with factor
    change_times = np.concatenate((np.asarray([0]),change_times))[:-1] # add 0 at beginig remove last element
    
    for i in range(len(scales)):          # send scales to scale_create
        scales[i,1] = scale_create(scales[i,1])
    pattern = np.tile(scales,(factor,1))   # tile the scales as long the melody is
    pattern[:,0] = change_times            #insert change_times into scales
    
#--end_scales
    end_scale= np.asarray(end_scale)
    end_times = melody_len - np.cumsum(( end_scale[:,0]*bpb )[::-1])[::-1]   # reversed cumsum subtracted of melody_len
    end_scale[:,0] = end_times              #insert end_times into en_scale
    for i in range(len(end_scale)):         # send end_scale to scale_create
        end_scale[i,1] = scale_create(end_scale[i,1])

#--merge
    pattern = np.delete(pattern, np.argwhere(pattern[:,0] >= end_scale[0,0]) ,0) # remove unneeded scales
    pattern = np.concatenate((pattern,end_scale),axis=0)
    pattern = np.delete(pattern, np.argwhere(pattern[:,0] >= melody_len) ,0)     # remove if end is 0 bars
    return pattern

   
def acceptance_melody(intvl, prob_intvl, pattern, start_note, a_range, notenr, rythem):
    melody = np.zeros(notenr, dtype=int)
    cum_rythem = np.cumsum(rythem) *4
    cum_rythem = np.concatenate(([0],cum_rythem))[:-1] # add 0 at beginig remove last element
    scale_change = pattern[:,0]
    scale_nr =0
    scale = pattern[scale_nr,1]
    melody[0] = scale[i_last_note(start_note,scale)]
    
    for npn in range(1, notenr):  #npn: note per note (index)      
        scale_nr = np.ravel(np.argwhere(scale_change <= cum_rythem[npn-1])) [-1]     
        scale = pattern[scale_nr,1]

        accept = False    
        while not accept:       # aslong acept == False
            inote = i_last_note(melody[npn-1],scale)
            inote_next = inote + intvl_next(intvl, prob_intvl)         # add current not with Proposition
            accept_val = a_range[[melody[(npn-1)],scale[inote_next]]]  # get acceptance values
            accept = acceptance(accept_val[0],accept_val[1])
        melody[npn] = scale[inote_next]
    return melody

#   plot_range: plot all ranges together
def plot_range(ranges,labels,title):
    fig, ax = plt.subplots()
    plt.xlabel('Midi Note')
    plt.ylabel('Acceptance')
    plt.title(title)

    for a_range, lab in zip(ranges,labels):
        ax.plot(range(121), a_range,label= lab, lw=4 )
        ax.fill_between(range(121), a_range, alpha= 0.15)
    ax.vlines(x=np.linspace(0,108, num=10), ymin=-5, ymax=5, color='grey', label='Octaves',linewidth=1.5) # plot octaves
    plt.legend()
    plt.savefig("range.svg")
    plt.show()
    
    
    
    
# [[[[[[[[[[[[[[[[[[[   -- Functions for Meteo Transformation --    ]]]]]]]]]]]]]]]]]]]




# [[[[[[[[[[[[[[[[[[[   -- Functions for Sound generation --    ]]]]]]]]]]]]]]]]]]]

import subprocess
default_soundfont = '/usr/share/sounds/sf3/MuseScore_General.sf3'

def midi_play(midi_in, soundfont= default_soundfont):
    subprocess.call(['cvlc', midi_in , 'vlc://quit', '--soundfont', '/home/viturin/-vitis/Documents/MuseScore2/Soundfonts/Compifont_13082016.sf2'])   # cvlc = vlc without gui
    
def midi_audio(midi_in, name_out = 'none', soundfont= default_soundfont):
    if name_out == 'none' :
        name_out = midi_in.replace('.mid', '.flac')
    else:
        name_out = name_out + '.flac'
    subprocess.call(['mscore', '-o', name_out, midi_in]) # -o = export as

def midi_png(midi_in, name_out = 'none'):
    if name_out == 'none' :
        name_out = midi_in.replace('.mid', '.png')
    else:
        name_out = name_out + '.png'
    subprocess.call(['mscore', '-o', name_out, '-T', '2', midi_in]) # -o = export as , -T 2 = cut page with 2 pixel