Пример #1
0
def test_sine_tone():
    """The wavetable is repeated through the tone."""
    # Calculate the envelope so we can divide it out of the generated sample
    envelope = tone(wavetable=Wavetable.from_function(lambda t: 1))
    pitch = 50.0
    sound = tone(pitch=pitch)

    samples = []
    expected = []

    for i in range(1000, 44100, 1000):
        t = i / 44100.0
        phase = (t * pitch) % 1.0 * tau
        sample = sound[i]
        env = envelope[i]
        samples.append(sample / env)
        expected.append(sin(phase))

    assert samples == approx(expected, abs=0.05)
Пример #2
0
 def on_click(self, pos):
     super().on_click(pos)
     print("tone = pyfxr.tone(",
           f"    {self.note!r}",
           "    attack=0.05,",
           "    sustain=0.0,",
           "    release=0.1,",
           "    wavetable=wavetable,",
           ")",
           sep="\n")
     s = pygame.mixer.Sound(buffer=pyfxr.tone(self.note,
                                              attack=0.05,
                                              sustain=0.0,
                                              release=0.1,
                                              wavetable=Waveform.current))
     s.set_volume(0.5)
     s.play()
Пример #3
0
def test_adsr_envelope():
    """Tones are modulated by an ADSR envelope."""
    w = Wavetable.from_function(lambda t: 1)
    sound = tone(attack=0.1,
                 decay=0.1,
                 sustain=0.75,
                 release=0.25,
                 wavetable=w)

    def sample_at(t: float) -> float:
        """Get the (float) value of the waveform at time t."""
        return sound[min(int(t * 44100), len(sound) - 1)] / (1 << 15)

    samples = list(map(
        sample_at,
        [0, 0.05, 0.1, 0.2, 0.5, 0.95, 1.2],
    ))

    assert samples == approx([0, 0.5, 1.0, 0.7, 0.7, 0.7, 0], abs=1e-3)
Пример #4
0
def _create(params):
    """Actually create a tone."""
    # Construct a mono tone of the right length
    tone = pyfxr.tone(
        pitch=params.hz,
        sustain=max(0, params.duration - 0.2),
        wavetable=params.waveform.value,
    )

    # NB. pygame assumes that the sound format of any buffer object matches
    # that of the current mixer settings. We use mixer.pre_init(22050, -16, 2)
    # which means that it is expecting 22kHz audio stereo, but we're feeding it
    # 44kHz mono - but, perhaps surprisingly, that works Ok. The extra samples
    # get interpreted as the second channel.
    #
    # If we change the mixer to 44kHz we'd need to convert to stereo here by
    # doubling samples.
    #
    # Really this is a mess and Pygame should support converting the format
    # of buffers (as it does for .wav files).
    snd = pygame.mixer.Sound(buffer=tone)
    snd.set_volume(params.volume)
    return snd
Пример #5
0
from math import sin
import pyglet.media
import pyfxr

window = pyglet.window.Window()

wt = pyfxr.Wavetable.from_function(
    lambda t: 0.75 * sin(t) + 0.25 * sin(3 * t + 0.5))
tone = pyfxr.tone(pitch='A4')
#tone = pyfxr.pluck(duration=1.0, pitch='A4')
source = pyglet.media.StaticSource(tone)


@window.event
def on_mouse_press(x, y, button, modifiers):
    source.play()


pyglet.app.run()