A channel utility class to mix several channels in one.
Module audioopy
Class ChannelMixer
Description
Constructor
Create a ChannelMixer instance.
View Source
def __init__(self):
"""Create a ChannelMixer instance."""
self._channels = []
self._factors = []
Public functions
get_channel
Return the channel of a given index.
Parameters
- idx: (int) the index of the channel to return
Returns
- (Channel)
View Source
def get_channel(self, idx):
"""Return the channel of a given index.
:param idx: (int) the index of the channel to return
:returns: (Channel)
"""
return self._channels[idx]
append_channel
Append a channel and the corresponding factor for a mix.
Parameters
- channel: (Channel object) the channel to append
- factor: (float) the factor associated to the channel
View Source
def append_channel(self, channel, factor=1):
"""Append a channel and the corresponding factor for a mix.
:param channel: (Channel object) the channel to append
:param factor: (float) the factor associated to the channel
"""
self._channels.append(channel)
self._factors.append(factor)
check_channels
Checking the conformity of the channels.
View Source
def check_channels(self):
"""Checking the conformity of the channels."""
if len(self._channels) == 0:
raise MixChannelError
sampwidth = self._channels[0].get_sampwidth()
framerate = self._channels[0].get_framerate()
nframes = self._channels[0].get_nframes()
for i in range(1, len(self._channels)):
if self._channels[i].get_sampwidth() != sampwidth:
raise MixChannelError(1)
if self._channels[i].get_framerate() != framerate:
raise MixChannelError(2)
if self._channels[i].get_nframes() != nframes:
raise MixChannelError(3)
mix
Mix the channels of the list in one.
Parameters
- attenuator: (float) the factor to apply to each sample calculated
Returns
- the result Channel
View Source
def mix(self, attenuator=1):
"""Mix the channels of the list in one.
:param attenuator: (float) the factor to apply to each sample calculated
:return: the result Channel
"""
self.check_channels()
sampwidth = self._channels[0].get_sampwidth()
framerate = self._channels[0].get_framerate()
frames = b''
if sampwidth == 4:
for s in range(0, len(self._channels[0].get_frames()), sampwidth):
value = ChannelMixer._sample_calculator(self._channels, s, sampwidth, self._factors, attenuator)
try:
frames += struct.pack('<l', long(value))
except:
frames += struct.pack('<l', int(value))
elif sampwidth == 2:
for s in range(0, len(self._channels[0].get_frames()), sampwidth):
value = ChannelMixer._sample_calculator(self._channels, s, sampwidth, self._factors, attenuator)
frames += struct.pack('<h', int(value))
else:
for s in range(0, len(self._channels[0].get_frames()), sampwidth):
value = ChannelMixer._sample_calculator(self._channels, s, sampwidth, self._factors, attenuator)
frames += struct.pack('<b', int(value))
return Channel(framerate, sampwidth, frames)
get_minmax
Return a tuple with the minimum and the maximum samples values.
Returns
- the tuple(minvalue, maxvalue)
View Source
def get_minmax(self):
"""Return a tuple with the minimum and the maximum samples values.
:return: the tuple (minvalue, maxvalue)
"""
self.check_channels()
sampwidth = self._channels[0].get_sampwidth()
minval = 0
maxval = 0
sampsum = 0
for s in range(0, len(self._channels[0].get_frames()), sampwidth):
value = ChannelMixer._sample_calculator(self._channels, s, sampwidth, self._factors, 1)
try:
sampsum = long(value)
except:
sampsum = int(value)
maxval = max(sampsum, maxval)
minval = min(sampsum, minval)
return (minval, maxval)
norm_length
Normalize the number of frames of all the channels, by appending silence at the end.
View Source
def norm_length(self):
"""Normalize the number of frames of all the channels,
by appending silence at the end.
"""
nframes = 0
for i in range(len(self._channels)):
nframes = max(nframes, self._channels[i].get_nframes())
for i in range(len(self._channels)):
if self._channels[i].get_nframes() < nframes:
fragment = ChannelFrames(self._channels[i].get_frames())
fragment.append_silence(nframes - self._channels[i].get_nframes())
self._channels[i] = Channel(self._channels[i].get_framerate(), self._channels[i].get_sampwidth(), fragment.get_frames())
Private functions
_sample_calculator
Return the sample value, applying a factor and an attenuator.
Parameters
- channels: (Channel[]) the list of channels
- pos: (int) the position of the sample to calculate
- sampwidth: (int) the sample width
- factors: (float[]) the list of factors to apply to each sample of a channel (1 channel = 1 factor)
- attenuator: (float) a factor to apply to each sum of samples
Returns
- (float) the value of the sample calculated
View Source
@staticmethod
def _sample_calculator(channels, pos, sampwidth, factors, attenuator):
"""Return the sample value, applying a factor and an attenuator.
:param channels: (Channel[]) the list of channels
:param pos: (int) the position of the sample to calculate
:param sampwidth: (int) the sample width
:param factors: (float[]) the list of factors to apply to each sample of a channel (1 channel = 1 factor)
:param attenuator: (float) a factor to apply to each sum of samples
:return: (float) the value of the sample calculated
"""
minval = float(ChannelFrames().get_minval(sampwidth))
maxval = float(ChannelFrames().get_maxval(sampwidth))
sampsum = 0
for factor, channel in zip(factors, channels):
data = channel.get_frames()[pos:pos + sampwidth]
data = AudioConverter().unpack_data(data, sampwidth, 1)
data = data[0]
sampsum += data[0] * factor * attenuator
if sampsum < 0:
return max(sampsum, minval)
elif sampsum > 0:
return min(sampsum, maxval)
return 0.0