About note and bar

Hey, MarcEvanstein,you have done a great job.I am a music producer. I use Cubase to make music.I want to say all the package I used that scamp is the best writing midi script in python. I think it has advantages as follows: first, it can be used in python,which makes coding much easier. Second, it can send midi signal to other sofftware,which makes it can use high quality vst instruments(trust me it could be a good assistant to make pro music). Third, it can fork. in music it means several instruments play at the same time,which also means you can create a vitual band and try all possible combination in music.
I have watch all the scamp videos. however, I got some questions when using it.first, about the bar concept, in music , a bar normally means you have four beats in it, in every beat you can divide it into 4times (16th notes), 8 times(32th notes). when you set a tempo the time for the bar is set.I can not find bar in scamp. Second, writting notes. when it comes to solo insruments and drums it’s good. but writing accompanied piano or acoustic guitar ,the job is huge, because the rhythm for guitar or piano changes a lot. all the questions could be solved by the following ways.
the key issue is that,when we told python to play a music to paly a note we should tell it ,in a set time,when the note begins to play , the length of the note(also means play how long to stop), the pitch, the voluem, in python def a note (pitch,volume,starttime,length), that it solves lots of problem.
for example, writing a drums could be done by set a bar (each bar has 3 lists to in store information s of pitch,volumen, startime, length) users only have to fill in the list ,then a drums is created. like:
tempo=90
pitch_and _startimel_list=[bassdrum,hihat,snare,hihat,bassdrum,hihat,snare,hihat,],(Ichoose to divide a bar in to 8times, which tells python first i play bassdrum(pitch stands for drum ),second I play hihat pitch,ect.) # user can choose quantize of the bar like(4times, 8times,16times,32times…)
volume_list=[1,0.8,0.9,0,8,1,0.8,0.9,0,8]
lenth-list=[16th,16th,16th,16th,16th,16th,16th,16th,]
this could make music by scamp much easier. hope this could help.

2 Likes

Hello yison,

Like you said, you have the full power of python available to build whatever abstraction you want.
Here’s an example of how you can make a simple drum machine using patterns.
Currently I’ve written the code to send midi information to an integra-7 midi synthesizer, but you can adapt the code to send to a vst or change the code to use a built-in synth instead.

import scamp
from collections import namedtuple

Line = namedtuple('Line', ['pattern', 'instr', 'subdiv'])

percmap = {
    'laser': 27,
    'whip': 28,
    'scratchpush': 29,
    'scratchpull': 30,
    'stickclick': 31,
    'metronomeclick': 32,
    'metronomebell': 34,
    'bassdrum': 35,
    'kickdrum': 36,
    'snarecrossstick': 37,
    'snaredrum': 38,
    'handclap': 39,
    'electricsnaredrum': 40,
    'floortom2': 41,
    'hihatclosed': 42,
    'floortom1': 43,
    'hihatfoot': 44,
    'lowtom': 45,
    'hihatopen': 46,
    'lowmidtom': 47,
    'highmidtom': 48,
    'crashcymbal': 49,
    'hightom': 50,
    'ridecymbal': 51,
    'chinacymbal': 52,
    'ridebell': 53,
    'tambourine': 54,
    'splashcymbal': 55,
    'cowbell': 56,
    'crashcymbal2': 57,
    'vibraslap': 58,
    'ridecymbal2': 59,
    'highbongo': 60,
    'lowbongo': 61,
    'congadeadstroke': 62,
    'conga': 63,
    'tumba': 64,
    'hightimbale': 65,
    'lowtimbale': 66,
    'highagogo': 67,
    'lowagogo': 68,
    'cabasa': 69,
    'maracas': 70,
    'whistleshort': 71,
    'whistlelong': 72,
    'guiroshort': 73,
    'guirolong': 74,
    'claves': 75,
    'highwoodblock': 76,
    'lowwoodblock': 77,
    'cuicahigh': 78,
    'cuicalow': 79,
    'trianglemute': 80,
    'triangleopen': 81,
    'shaker': 82,
    'sleighbell': 83,
    'belltree': 84,
    'castagnets': 85,
    'surdudeadstroke': 86,
    'surdu': 87,
    'snaredrumrod': 91,
    'oceandrum': 92,
    'snaredrumbrush': 93
    # add your own here
}

symbol_to_volume = {
    'X': 1.0,
    'x': 0.9,
    'o': 0.8
    # add your own here
}


def play_line(line, instrument):
    duration = 1.0 / line.subdiv
    midinote = percmap[line.instr]
    for symbol in line.pattern:
        if symbol == '.':
            scamp.wait(duration)
        else:
            volume = symbol_to_volume[symbol]
            instrument.play_note(midinote, volume, duration, blocking=True)


def pattern_to_music(session, instrument, pat, repeats=1):
    for _ in range(repeats):
        for line in pat:
            scamp.fork(play_line, args=(line, instrument))
        session.wait_for_children_to_finish()


def main():
    pattern = {
        'takemetothemardigras' : [
            Line("X.........X..X..X..X......X.....", 'kickdrum', 4),
            Line("....X.......X.......X..X.X..X...", 'snaredrum', 4),
            Line("X.X.X.XXX.X.X.XXX...X.XXX.X.X...", 'hihatclosed', 4),
            Line("..............................X.", 'hihatopen', 4),
            Line("X.X..X...X..X...X.X..X...X..X...", 'highagogo', 4),
            Line("....X..X..X..X.X....X..X..X..X.X", 'lowagogo', 4),
        ],
        'amenbrother': [
            Line("X.X.......XX....X.X.......XX....X.X.......X.......XX......X.....", 'kickdrum', 4),
            Line("....X..X.X..X..X....X..X.X..X..X....X..X.X....X..X..X..X.X....X.", 'snaredrum', 4),
            Line("X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X...X.X.", 'ridecymbal', 4),
            Line("..........................................................X.....", 'hihatopen', 4),
            # add your own here
        ],
        # add your own here
    }
    s = scamp.session.Session(tempo=120)
    drums = s.new_midi_part(name="drums",
                            midi_output_device='INTEGRA-7:INTEGRA-7 MIDI 1 24:0',
                            num_channels=1,
                            midi_output_name="drums",
                            start_channel=9)
    pattern_to_music(session=s,
                     instrument=drums,
                     pat=pattern['takemetothemardigras'],
                     repeats=4)

if __name__ == "__main__":
    main()

1 Like

@shiihs Awesome example — I was just going to reply with something along these lines, but I didn’t have something fleshed out like this!

That said, @yison, your question made me wonder whether there’s some value to a play_notes utility function, which would take a list of pitches, a list of volumes, and a list of durations. Would other people find this valuable, or is it better to have people build their own?

amazing, you create somthinglike text to music, the user only have to asign to what note to play and care less about how to code.

from scamp import *

s = Session(tempo=85)
guitar = s.new_part("guitar", )
guitar1 = s.new_part("guitar", )
guitar2 = s.new_part("guitar", )
guitar3 = s.new_part("guitar", )
guitar4 = s.new_part("guitar", )
guitar5 = s.new_part("guitar", )
guitar6 = s.new_part("guitar", )
guitar7 = s.new_part("guitar", )
guitar8 = s.new_part("guitar", )
# scamp does a great job when do solo instrument and time equal notes
#  a guitar player when playing harmony part he will sustain some notes, meaning same times some notes playing longer some notes play shorter, this coding shows that how to play sustain notes and different time and you will see lots of codes just one bar 

keyboard = ['C-2', 'C#-2', 'D-2', 'D#-2', 'E-2', 'F-2', 'F#-2', 'G-2', 'G#-2', 'A-2', 'A#-2', 'B-2', 'C-1', 'C#-1',
            'D-1', 'D#-1', 'E-1', 'F-1', 'F#-1', 'G-1', 'G#-1', 'A-1', 'A#-1', 'B-1', 'C0', 'C#0', 'D0', 'D#0', 'E0',
            'F0', 'F#0', 'G0', 'G#0', 'A0', 'A#0', 'B0', 'C1', 'C#1', 'D1', 'D#1', 'E1', 'F1', 'F#1', 'G1', 'G#1', 'A1',
            'A#1', 'B1', 'C2', 'C#2', 'D2', 'D#2', 'E2', 'F2', 'F#2', 'G2', 'G#2', 'A2', 'A#2', 'B2', 'C3', 'C#3', 'D3',
            'D#3', 'E3', 'F3', 'F#3', 'G3', 'G#3', 'A3', 'A#3', 'B3', 'C4', 'C#4', 'D4', 'D#4', 'E4', 'F4', 'F#4', 'G4',
            'G#4', 'A4', 'A#4', 'B4', 'C5', 'C#5', 'D5', 'D#5', 'E5', 'F5', 'F#5', 'G5', 'G#5', 'A5', 'A#5', 'B5', 'C6',
            'C#6', 'D6', 'D#6', 'E6', 'F6', 'F#6', 'G6', 'G#6', 'A6', 'A#6', 'B6', 'C7', 'C#7', 'D7', 'D#7', 'E7', 'F7',
            'F#7', 'G7', 'G#7', 'A7', 'A#7', 'B7', 'C8', 'C#8', 'D8', 'D#8', 'E8', 'F8', 'F#8', 'G8', 'G#8', 'A8',
            'A#8', 'B8']


def play_guitar():
    guitar.play_note(keyboard.index("C2"), 0.46, 4, )


def play_guitar1():
    wait(0.5)
    guitar1.play_note(keyboard.index("G2"), 0.6, 3.5, )


def play_guitar2():
    wait(1)
    guitar2.play_note(keyboard.index("E3"), 0.32, 3, )


def play_guitar3():
    wait(2)
    guitar3.play_note(keyboard.index("D3"), 0.32, 2, )


def play_guitar4():
    wait(2.5)
    guitar4.play_note(keyboard.index("G2"), 0.32, 1, )


def play_guitar5():
    wait(3)
    guitar5.play_note(keyboard.index("E3"), 0.32, 1, )


while True:
    s.fork(play_guitar)
    s.fork(play_guitar1)
    s.fork(play_guitar2)
    s.fork(play_guitar3)
    s.fork(play_guitar4)
    s.fork(play_guitar5)

    s.wait_for_children_to_finish()

here is a samll band bar loop using scamp

# i think an easy way to make music could like this
# lis1_8=[note,note,note,0,note,note,note,0] start_time pitch list (the list you can fill note or empty)(divide the bar equally 8times)
# when 16th note star_time is involved,user can choose list1_16th=[]
# or combine two notes or chord lis1_8=[{note,note,},note,note,0,note,note,note,0]
# lis1_example=[C2,G2,E3,0,D3,G2,E3,0] it looks like the pic of  "guitar harmony player"
# lis2=[4beat,2beat,2beat,2beat,1beat,1beat] length list.  it looks like the pic of  "guitar harmony player" (the length could be difficult to explain 1bar=4beat,1beat=8*32th=4*16th=2*8th=1*4th
# this is harmony writing way you could see that it has a pattern if the note only play one time that it last to the end ect...
# volume=0.8 means all of the note_volume=0.8, in fact,in all the daw the range is (0,127)
# guitar_lis1=[lis1,lis2]
# bar1.play(guitar_lis1,drum_lis1,ect) play guitar ,drum ,at the same time by setting differnt channel

copy this to python
I don’t know how to achieve this goal, you a good coder maybe you could do it

Just a quick note: In SCAMP you can play a note with blocking=False, like this:

guitar.play_note(60, 0.8, 3, blocking=False)
wait(1)
guitar.play_note(64, 0.8, 2)

This causes the first note to start but not wait until it’s finished, so the result will be an overlap between the two notes. I think this is what you we’re trying to accomplish with all of the fork calls you were doing.

By the way, you might consider taking my Kadenze course. It’s not too expensive, and I think it would really help you with understanding SCAMP. (It talks about blocking=False, for example. Also, it supports me financially, which is a very much appreciated if you are able!

still have to say when coding a simply harmony bar ,the job is huge , shiihs gave a good example how to set starttime ,and it is striaight forward. if you want to run his code,you should download loopmidi and s.print, find your midi port and replace his midi device ,set the port in the daw then you will hear. I think you should download a cubase or reaper .

this is how musicpy writes music(add “wait=True” in the play line)

still working on setting midi ports

The point of coding in Python is to create abstractions for the kind of thing you want to do. So in your case, in order to do arpeggios on the guitar where the notes are held until the end of the bar, you could create a function:

def play_held_arpeggio(inst, pitches, volumes, note_length, total_length):
    t = 0
    for p, v in zip(pitches, volumes):
        inst.play_note(p, v, total_length - t, blocking=False)
        wait(note_length)
        t += note_length
    wait(total_length - t)

And then loop a simple chord progression like this:

while True:
    play_held_arpeggio(guitar, [45, 52, 59, 57, 60], [0.9, 0.6, 0.8, 0.5, 0.8], 0.25, 3.0)
    play_held_arpeggio(guitar, [43, 52, 59], [0.9, 0.6, 0.8], 0.25, 2.0)
    play_held_arpeggio(guitar, [41, 50, 59, 57, 60], [0.9, 0.6, 0.8, 0.5, 0.8], 0.25, 3.0)
    play_held_arpeggio(guitar, [40, 47, 56, 62], [0.9, 0.6, 0.6, 0.8], 1/3, 2.0)

The beauty of this is that you only ever have to write this function one time, and then you can use it whenever you need it.

If you want to try it out, here’s the full code of the example:

from scamp import *

s = Session()

guitar = s.new_part("guitar")


def play_held_arpeggio(inst, pitches, volumes, note_length, total_length):
    t = 0
    for p, v in zip(pitches, volumes):
        inst.play_note(p, v, total_length - t, blocking=False)
        wait(note_length)
        t += note_length
    wait(total_length - t)
    

while True:
    play_held_arpeggio(guitar, [45, 52, 59, 57, 60], [0.9, 0.6, 0.8, 0.5, 0.8], 0.25, 3.0)
    play_held_arpeggio(guitar, [43, 52, 59], [0.9, 0.6, 0.8], 0.25, 2.0)
    play_held_arpeggio(guitar, [41, 50, 59, 57, 60], [0.9, 0.6, 0.8, 0.5, 0.8], 0.25, 3.0)
    play_held_arpeggio(guitar, [40, 47, 56, 62], [0.9, 0.6, 0.6, 0.8], 1/3, 2.0)

Yeah,it’s the coding i like ,if fixes everything. You are talented