Ejemplo n.º 1
0
def pitch_unidir(time, correct):
    """
    Unidirectional pitch-shift into a specified pitch.

    Starts at most 3 semitones away from the desired pitch.
    """
    trans = ratio(window(1.) + correct)
    origin = ratio(correct)
    return interleave([trans, origin], [0., time * 1000], [1, window(.75)])
Ejemplo n.º 2
0
def perc(pitch, time, instrument):
    """
    Engine Main.

    Returns an odot bundle for the perc engine. API:
    /engine : "perc"
    /samples: (string) -- a sample to use
    /suffix : (string) -- filename suffix
    /time : (float) -- total time in seconds
    /pitch : (float) -- transposition factor
    /amp : (list) -- line~ list for amplitude envelope
    """
    categories = autocat[instrument]

    categories = filterCategories(pitch, instrument, categories)
    if len(categories) is 0:
        return o.bundle()

    query = one(getSamples(pitch, instrument, categories))
    correct = pitch - query["midi"]
    sample = query["files"]

    oengine = o.message("/engine", "perc")
    osamp = o.message("/samples", sample)
    ofilename = o.message("/suffix", "_" + instrument + "_perc.wav")
    otime = o.message("/time", time)
    opitch = o.message("/pitch", ratio(correct))
    oamps = o.message("/amp", amp_env(time))
    return o.bundle(messages=[oengine, osamp, ofilename, otime, opitch, oamps])
Ejemplo n.º 3
0
def pitch_peak(time, correct):
    """
    A triangle-wave-like pitch shift.

    Moves up / down from no-transposition and returns to normal.
    Guaranteed to reach its destination within the first 75% of
    the time requested.
    """
    ms = lambda t: _ms(t, time)
    trans = ratio(window(1.) + correct)
    origin = ratio(correct)
    attack_time = random() * .75 + .2
    decay_time = 1. - attack_time
    dest = [origin, trans, origin]
    times = [0., ms(attack_time), ms(decay_time)]
    curves = [1.] + window([.75, .75])
    return interleave(dest, times, curves)
Ejemplo n.º 4
0
def rapids(chord, time, instrument):
    """
    Rapids event generator.

    Returns an odot bundle for the rapids engine. API:
    /engine : "rapids"
    /instrument : (string) -- instrument used
    /samples : (list) -- a list of samples for polybuffer~
    /suffix : (string) -- filename suffix
    /time : (float) -- total time in seconds
    /events : (list of bundles) -- bundles containing all of the
              information to play back a list of samples, rapidly.
    """
    # Figure out event times and update time if necessary:
    event_times, time = rapids_time(chord, time)

    # Figure out useful articulation categories:
    categories = []
    for pitch in chord:
        categories.append(filterCategories(pitch, instrument, autocat[instrument]))

    # create a dictionary of sound queries to be resolved by getSamples:
    soundqueries = [{'pitch' : elem[0], 'artic': elem[1]} for elem in collect(chord, categories)
                    if not(not elem[1])] # discard impossible notes (empty category)
    
    # execute the query, giving us the samples we'd need:
    seqfiles = [one(getSamples(sq['pitch'], instrument, sq['artic'])) for sq in soundqueries]
    
    print('-' * 100)
    print(len(soundqueries) == len(seqfiles))
    print('-' * 100)
    
    # determine transposition ratios for sample playback:
    #correct = [pitch - ratio(sample['midi']) for sample in seqfiles]
    correct = [ratio(pair[0]['pitch'] - pair[1]['midi']) for pair in collect(soundqueries, seqfiles)]

    # filter redundant files:
    filenames = [e for e in set([sample['files'] for sample in seqfiles])]

    # determine the index of sample playback in polybuffer~:
    fileindices = [filenames.index(filename) + 1 for filename in [sq['files'] for sq in seqfiles]]

    # construct bundle:
    oengine = o.message('/engine', 'rapids')
    oinstr = o.message('/insturment', instrument)
    osamp = o.message('/samples', filenames)
    osuffix = o.message('/suffix', '_' + instrument + '_rapids.wav')
    otime = o.message('/time', time)
    events = []
    for index, value in enumerate(fileindices):
        opitch = o.message('/pitch', correct[index])
        obuffer = o.message('/buffer', instrument + '.rapids.' + str(value))
        oeventtime = o.message('/event/time', event_times[index] + 0.02)
        events.append(o.bundle(messages = [opitch, obuffer, oeventtime]))
    oevents = o.message('/events', events)
    return o.bundle(messages = [oengine, oinstr, osamp, osuffix, otime, oevents])
Ejemplo n.º 5
0
def pitch_cross(time, correct):
    """
    Shifts up then down (or down then up), before returning to
    the original pitch of the sample.
    """
    ms = lambda t: _ms(t, time)
    _ts = lambda: random() * .33 + .1
    shifts = window([1., 1.])
    if (shifts[0] * shifts[1]) > 0:
        shifts[one([0, 1])] *= -1
    trans = []
    for s in shifts:
        trans.append(s + correct)
    trans = ratio(trans)
    first = _ts()
    second = 1 - _ts() - first
    decay = 1. - (first + second)
    origin = ratio(correct)
    dest = [origin] + trans + [origin]
    times = [0., ms(first), ms(second), ms(decay)]
    curves = [1.] + window([.75, .75, .75])
    return interleave(dest, times, curves)
Ejemplo n.º 6
0
def reartic(pitch, time, instrument):
    """
    Rearticulation event generator.

    Returns an odot bundle for the rearticulation engine. API:
    /engine : "reartic"
    /samples : (list) -- a list of samples for polybuffer~
    /suffix : (string) -- filename suffix
    /time : (float) -- total time in seconds
    /events : (list of bundles) -- time-tagged bundles containing
              all of the articulations & envelopes

    This engine is different from others due to the fact that it
    plays multiple sounds, arranged in time. (For this reason, the
    current implementation does not generalize engines into a helper
    structure yet, which violates DRY and will be fixed in time.)
    """
    # event_times = subdivide(time) # for o.schedule
    event_times, event_lengths = reartic_time(time)
    categories = []
    for event in event_lengths:
        categories.append(filterCategories(pitch, instrument, autocat[instrument]))

    soundqueries = [{'pitch': pitch, 'artic': category} for category in categories
                    if not (not category)] # discard impossible notes
    seqfiles = [one(getSamples(sq['pitch'], instrument, sq['artic'])) for sq in soundqueries]
    correct = [ratio(pitch - sound['midi']) for sound in seqfiles]
    filenames = [e for e in set([sample['files'] for sample in seqfiles])]
    fileindices = [filenames.index(filename) + 1 for filename in [sq['files'] for sq in seqfiles]]
    event_times = [e + .05 for e in event_times]

    oengine = o.message('/engine', 'reartic')
    oinstr = o.message('/instrument', instrument)
    osamp = o.message('/samples', filenames)
    osuffix = o.message('/suffix', '_' + instrument + '_reartic.wav')
    otime = o.message('/time', time)
    events = []
    envfuncs = [env_uniform, env_jagged, amp_in_out]
    for index, value in enumerate(fileindices):
        opitch = o.message('/pitch', correct[index])
        obuffer = o.message('/buffer', instrument + '.reartic.' + str(value))
        oeventtime = o.message('/event/time', event_times[index])
        oamp = o.message('/envelope', one(envfuncs)(event_lengths[index]))
        events.append(o.bundle(messages = [opitch, obuffer, oeventtime, oamp]))
    oevents = o.message('/events', events)
    return o.bundle(messages = [oengine, oinstr, osamp, osuffix, otime, oevents])