Пример #1
0
    def test_basic_api_usage(self):

        # this test is mostly documentation and coverage and is going to be
        # relatively free of assertions, because of the nature of the work

        # the opus is the framework for a composition.  It has a Python object
        # model which is also the basic API.  At a high level:
        # a song has tracks
        # a song has scenes
        # each scene chooses a pattern for each track
        # a scene might override the scale or BPM
        # each pattern has bars (which might repeat)
        # bars can be described in multiple types of systems
        # a pattern might override the scale (but can't override the BPM)
        # scenes might be manually advanced by a human, or they might not.

        # values set at the song level are essentially global defaults
        song = Song(name="Random Notes", scale=scale('c4 major'), pattern_length=16, bars=4, bpm=120)

        # tracks get mapped to MIDI channels but they also have printable names
        track1 = song.add_track(Track(name="melodica", midi_channel=1))
        track2 = song.add_track(Track(name="trombone", midi_channel=2))
        track3 = song.add_track(Track(name="TR808", midi_channel=2))

        # a pattern has a name, a notation system, and can optionally override a scale
        llama_pattern = Pattern(name="llama-theme", notation='roman', scale=scale('c4 minor'),
            bars = [
               Bar(cells="1 2 3 I II III IV i ii iii iv - 3 2 1".split()),
            ]
        )
        # here the pattern plays the first bar 3 times then the next bar 1 time
        sheep_pattern = Pattern(name="sheep-theme", notation='roman',
            bars = [
                Bar(cells="4 6 4 6 4 4 4 4 6 6 4 1 1 - - - -".split(), repeats=3),
                Bar(cells="4 6 4 6 4 4 4 4 6 4 6 1 . . . . .".split(), repeats=1)
            ]
        )
        # for drums, scales are pretty bogus, so just input the raw notes (or chords, etc)
        kick_pattern = Pattern(name="kicks", notation='literal',
            bars = [
                Bar(cells="C4 - - -".split(), stop=4)
            ]
        )

        # the song has a list of scenes, which might repeat
        scene1 = song.add_scene(Scene(name="scene1", track_mapping=dict(
            track1 = llama_pattern,
            track2 = sheep_pattern,
            track3 = kick_pattern
        )))

        # scenes can also override many of the global settings
        scene2 = song.add_scene(Scene(name="scene2", scale=scale('c5 minor'), bpm=140, bars=6, track_mapping=dict(
            track1 = llama_pattern,
            track2 = sheep_pattern,
            track3 = None
        )))

        # PSEUDOCODE SKETCH: TODO: real-time AND rendering will probably look like:
        # while True
        #     sleep(SMALL_NUMBER) # unless rendering
        #     events = song.advance_time(SMALL_NUMBER)
        #     for x in events
        #        send or print event
        # ??? - to be determined

        realtime = Realtime(song)
        #realtime.playback_test()

        realtime.play_song(callback=print_event)

        raise Exception("STOP")