Support for multiple sound waves (triangular, square and sawtooth)

This commit is contained in:
Fabio Manganiello 2018-12-26 23:14:52 +01:00
parent 3b681bbf57
commit 3598d7fcd5
2 changed files with 35 additions and 3 deletions

View file

@ -2,10 +2,18 @@
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com> .. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
""" """
import enum
import json import json
import math import math
class WaveShape(enum.Enum):
SIN='sin'
SQUARE='square'
SAWTOOTH='sawtooth'
TRIANG='triang'
class Sound(object): class Sound(object):
""" """
Models a basic synthetic sound that can be played through an audio device Models a basic synthetic sound that can be played through an audio device
@ -23,9 +31,11 @@ class Sound(object):
phase = 0.0 phase = 0.0
gain = 1.0 gain = 1.0
duration = None duration = None
shape = None
def __init__(self, midi_note=midi_note, frequency=None, phase=phase, def __init__(self, midi_note=midi_note, frequency=None, phase=phase,
gain=gain, duration=duration, A_frequency=STANDARD_A_FREQUENCY): gain=gain, duration=duration, shape=WaveShape.SIN,
A_frequency=STANDARD_A_FREQUENCY):
""" """
You can construct a sound either from a MIDI note or a base frequency You can construct a sound either from a MIDI note or a base frequency
@ -46,6 +56,10 @@ class Sound(object):
release/pause/stop release/pause/stop
:type duration: float :type duration: float
:param shape: Wave shape. Possible values: "``sin``", "``square``" or
"``triang``" (see :class:`WaveSound`). Default: "``sin``"
:type shape: str
:param A_frequency: Reference A4 frequency (default: 440 Hz) :param A_frequency: Reference A4 frequency (default: 440 Hz)
:type A_frequency: float :type A_frequency: float
""" """
@ -69,6 +83,7 @@ class Sound(object):
self.phase = phase self.phase = phase
self.gain = gain self.gain = gain
self.duration = duration self.duration = duration
self.shape = WaveShape(shape)
@classmethod @classmethod
def note_to_freq(cls, midi_note, A_frequency=STANDARD_A_FREQUENCY): def note_to_freq(cls, midi_note, A_frequency=STANDARD_A_FREQUENCY):
@ -122,7 +137,23 @@ class Sound(object):
x = np.linspace(t_start, t_end, int((t_end-t_start)*samplerate)) x = np.linspace(t_start, t_end, int((t_end-t_start)*samplerate))
x = x.reshape(len(x), 1) x = x.reshape(len(x), 1)
return self.gain * np.sin((2*np.pi*self.frequency*x) + np.pi*self.phase)
if self.shape == WaveShape.SIN or self.shape == WaveShape.SQUARE:
wave = np.sin((2*np.pi*self.frequency*x) + np.pi*self.phase)
if self.shape == WaveShape.SQUARE:
wave[wave < 0] = -1
wave[wave >= 0] = 1
elif self.shape == WaveShape.SAWTOOTH:
wave = 2 * (self.frequency*x -
np.floor(0.5 + self.frequency*x))
elif self.shape == WaveShape.TRIANG:
wave = 2 * np.abs(2 * (self.frequency*x -
np.floor(0.5 + self.frequency*x))) -1
else:
raise RuntimeError('Unsupported wave shape: {}'.format(self.shape))
return self.gain * wave
def __iter__(self): def __iter__(self):

View file

@ -582,7 +582,8 @@ class SoundPlugin(Plugin):
for i, stream in streams.items(): for i, stream in streams.items():
stream['playback_state'] = self.playback_state[i].name stream['playback_state'] = self.playback_state[i].name
if i in self.stream_mixes: if i in self.stream_mixes:
stream['mix'] = list(self.stream_mixes[i]) stream['mix'] = { j: sound for j, sound in
enumerate(list(self.stream_mixes[i])) }
return streams return streams