def dcshift(self, shift=0.0):
        '''Apply a DC shift to the audio.

        Parameters
        ----------
        shift : float
            Amount to shift audio between -2 and 2. (Audio is between -1 and 1)

        See Also
        --------
        highpass

        '''
        if not is_number(shift) or shift < -2 or shift > 2:
            raise ValueError('shift must be a number between -2 and 2.')

        effect_args = ['dcshift', '{:f}'.format(shift)]

        self.effects.extend(effect_args)
        self.effects_log.append('dcshift')
        return self


def delay(self, positions):
        '''Delay one or more audio channels such that they start at the given
        positions.

        Parameters
        ----------
        positions: list of floats
            List of times (in seconds) to delay each audio channel.
            If fewer positions are given than the number of channels, the
            remaining channels will be unaffected.

        '''
        if not isinstance(positions, list):
            raise ValueError("positions must be a a list of numbers")

        if not all((is_number(p) and p >= 0) for p in positions):
            raise ValueError("positions must be positive nubmers")

        effect_args = ['delay']
        effect_args.extend(['{:f}'.format(p) for p in positions])

        self.effects.extend(effect_args)
        self.effects_log.append('delay')
        return self

def
delay
(
self
,
positions
)
:
if
not
isinstance
(
positions
,
list
)
:
raise
ValueError
(
"positions must be a a list of numbers"
)
if
not
all
(
(
is_number
(
p
)
and
p
>=
0
)
for
p
in
positions
)
:
raise
ValueError
(
"positions must be positive nubmers"
)
effect_args
=
[
'delay'
]
effect_args
.
extend
(
[
'{:f}'
.
format
(
p
)
for
p
in
positions
]
)
self
.
effects
.
extend
(
effect_args
)
self
.
effects_log
.
append
(
'delay'
)
return
self

Delay one or more audio channels such that they start at the given positions .


def downsample(self, factor=2):
        '''Downsample the signal by an integer factor. Only the first out of
        each factor samples is retained, the others are discarded.

        No decimation filter is applied. If the input is not a properly
        bandlimited baseband signal, aliasing will occur. This may be desirable
        e.g., for frequency translation.

        For a general resampling effect with anti-aliasing, see rate.

        Parameters
        ----------
        factor : int, default=2
            Downsampling factor.

        See Also
        --------
        rate, upsample

        '''
        if not isinstance(factor, int) or factor < 1:
            raise ValueError('factor must be a positive integer.')

        effect_args = ['downsample', '{}'.format(factor)]

        self.effects.extend(effect_args)
        self.effects_log.append('downsample')
        return self

def
downsample
(
self
,
factor
=
2
)
:
if
not
isinstance
(
factor
,
int
)
or
factor
<
1
:
raise
ValueError
(
'factor must be a positive integer.'
)
effect_args
=
[
'downsample'
,
'{}'
.
format
(
factor
)
]
self
.
effects
.
extend
(
effect_args
)
self
.
effects_log
.
append
(
'downsample'
)
return
self

Downsample the signal by an integer factor . Only the first out of each factor samples is retained the others are discarded .


def echo(self, gain_in=0.8, gain_out=0.9, n_echos=1, delays=[60],
             decays=[0.4]):
        '''Add echoing to the audio.

        Echoes are reflected sound and can occur naturally amongst mountains
        (and sometimes large buildings) when talking or shouting; digital echo
        effects emulate this behav- iour and are often used to help fill out
        the sound of a single instrument or vocal. The time differ- ence
        between the original signal and the reflection is the 'delay' (time),
        and the loudness of the reflected signal is the 'decay'. Multiple
        echoes can have different delays and decays.

        Parameters
        ----------
        gain_in : float, default=0.8
            Input volume, between 0 and 1
        gain_out : float, default=0.9
            Output volume, between 0 and 1
        n_echos : int, default=1
            Number of reflections
        delays : list, default=[60]
            List of delays in miliseconds
        decays : list, default=[0.4]
            List of decays, relative to gain in between 0 and 1

        See Also
        --------
        echos, reverb, chorus
        '''
        if not is_number(gain_in) or gain_in <= 0 or gain_in > 1:
            raise ValueError("gain_in must be a number between 0 and 1.")

        if not is_number(gain_out) or gain_out <= 0 or gain_out > 1:
            raise ValueError("gain_out must be a number between 0 and 1.")

        if not isinstance(n_echos, int) or n_echos <= 0:
            raise ValueError("n_echos must be a positive integer.")

        # validate delays
        if not isinstance(delays, list):
            raise ValueError("delays must be a list")

        if len(delays) != n_echos:
            raise ValueError("the length of delays must equal n_echos")

        if any((not is_number(p) or p <= 0) for p in delays):
            raise ValueError("the elements of delays must be numbers > 0")

        # validate decays
        if not isinstance(decays, list):
            raise ValueError("decays must be a list")

        if len(decays) != n_echos:
            raise ValueError("the length of decays must equal n_echos")
        if any((not is_number(p) or p <= 0 or p > 1) for p in decays):
            raise ValueError(
                "the elements of decays must be between 0 and 1"
            )

        effect_args = ['echo', '{:f}'.format(gain_in), '{:f}'.format(gain_out)]

        for i in range(n_echos):
            effect_args.extend([
                '{}'.format(delays[i]),
                '{}'.format(decays[i])
            ])

        self.effects.extend(effect_args)
        self.effects_log.append('echo')
        return self


def flanger(self, delay=0, depth=2, regen=0, width=71, speed=0.5,
                shape='sine', phase=25, interp='linear'):
        '''Apply a flanging effect to the audio.

        Parameters
        ----------
        delay : float, default=0
            Base delay (in miliseconds) between 0 and 30.
        depth : float, default=2
            Added swept delay (in miliseconds) between 0 and 10.
        regen : float, default=0
            Percentage regeneration between -95 and 95.
        width : float, default=71,
            Percentage of delayed signal mixed with original between 0 and 100.
        speed : float, default=0.5
            Sweeps per second (in Hz) between 0.1 and 10.
        shape : 'sine' or 'triangle', default='sine'
            Swept wave shape
        phase : float, default=25
            Swept wave percentage phase-shift for multi-channel flange between
            0 and 100. 0 = 100 = same phase on each channel
        interp : 'linear' or 'quadratic', default='linear'
            Digital delay-line interpolation type.

        See Also
        --------
        tremolo
        '''
        if not is_number(delay) or delay < 0 or delay > 30:
            raise ValueError("delay must be a number between 0 and 30.")
        if not is_number(depth) or depth < 0 or depth > 10:
            raise ValueError("depth must be a number between 0 and 10.")
        if not is_number(regen) or regen < -95 or regen > 95:
            raise ValueError("regen must be a number between -95 and 95.")
        if not is_number(width) or width < 0 or width > 100:
            raise ValueError("width must be a number between 0 and 100.")
        if not is_number(speed) or speed < 0.1 or speed > 10:
            raise ValueError("speed must be a number between 0.1 and 10.")
        if shape not in ['sine', 'triangle']:
            raise ValueError("shape must be one of 'sine' or 'triangle'.")
        if not is_number(phase) or phase < 0 or phase > 100:
            raise ValueError("phase must be a number between 0 and 100.")
        if interp not in ['linear', 'quadratic']:
            raise ValueError("interp must be one of 'linear' or 'quadratic'.")

        effect_args = [
            'flanger',
            '{:f}'.format(delay),
            '{:f}'.format(depth),
            '{:f}'.format(regen),
            '{:f}'.format(width),
            '{:f}'.format(speed),
            '{}'.format(shape),
            '{:f}'.format(phase),
            '{}'.format(interp)
        ]

        self.effects.extend(effect_args)
        self.effects_log.append('flanger')

        return self


def gain(self, gain_db=0.0, normalize=True, limiter=False, balance=None):
        '''Apply amplification or attenuation to the audio signal.

        Parameters
        ----------
        gain_db : float, default=0.0
            Gain adjustment in decibels (dB).
        normalize : bool, default=True
            If True, audio is normalized to gain_db relative to full scale.
            If False, simply adjusts the audio power level by gain_db.
        limiter : bool, default=False
            If True, a simple limiter is invoked to prevent clipping.
        balance : str or None, default=None
            Balance gain across channels. Can be one of:
             * None applies no balancing (default)
             * 'e' applies gain to all channels other than that with the
                highest peak level, such that all channels attain the same
                peak level
             * 'B' applies gain to all channels other than that with the
                highest RMS level, such that all channels attain the same
                RMS level
             * 'b' applies gain with clipping protection to all channels other
                than that with the highest RMS level, such that all channels
                attain the same RMS level
            If normalize=True, 'B' and 'b' are equivalent.

        See Also
        --------
        loudness

        '''
        if not is_number(gain_db):
            raise ValueError("gain_db must be a number.")

        if not isinstance(normalize, bool):
            raise ValueError("normalize must be a boolean.")

        if not isinstance(limiter, bool):
            raise ValueError("limiter must be a boolean.")

        if balance not in [None, 'e', 'B', 'b']:
            raise ValueError("balance must be one of None, 'e', 'B', or 'b'.")

        effect_args = ['gain']

        if balance is not None:
            effect_args.append('-{}'.format(balance))

        if normalize:
            effect_args.append('-n')

        if limiter:
            effect_args.append('-l')

        effect_args.append('{:f}'.format(gain_db))
        self.effects.extend(effect_args)
        self.effects_log.append('gain')

        return self

Apply amplification or attenuation to the audio signal .


def loudness(self, gain_db=-10.0, reference_level=65.0):
        '''Loudness control. Similar to the gain effect, but provides
        equalisation for the human auditory system.

        The gain is adjusted by gain_db and the signal is equalised according
        to ISO 226 w.r.t. reference_level.

        Parameters
        ----------
        gain_db : float, default=-10.0
            Loudness adjustment amount (in dB)
        reference_level : float, default=65.0
            Reference level (in dB) according to which the signal is equalized.
            Must be between 50 and 75 (dB)

        See Also
        --------
        gain

        '''
        if not is_number(gain_db):
            raise ValueError('gain_db must be a number.')

        if not is_number(reference_level):
            raise ValueError('reference_level must be a number')

        if reference_level > 75 or reference_level < 50:
            raise ValueError('reference_level must be between 50 and 75')

        effect_args = [
            'loudness',
            '{:f}'.format(gain_db),
            '{:f}'.format(reference_level)
        ]
        self.effects.extend(effect_args)
        self.effects_log.append('loudness')

        return self

Loudness control . Similar to the gain effect but provides equalisation for the human auditory system .


def noiseprof(self, input_filepath, profile_path):
        '''Calculate a profile of the audio for use in noise reduction.
        Running this command does not effect the Transformer effects
        chain. When this function is called, the calculated noise profile
        file is saved to the `profile_path`.

        Parameters
        ----------
        input_filepath : str
            Path to audiofile from which to compute a noise profile.
        profile_path : str
            Path to save the noise profile file.

        See Also
        --------
        noisered

        '''
        if os.path.isdir(profile_path):
            raise ValueError(
                "profile_path {} is a directory.".format(profile_path))

        if os.path.dirname(profile_path) == '' and profile_path != '':
            _abs_profile_path = os.path.join(os.getcwd(), profile_path)
        else:
            _abs_profile_path = profile_path

        if not os.access(os.path.dirname(_abs_profile_path), os.W_OK):
            raise IOError(
                "profile_path {} is not writeable.".format(_abs_profile_path))

        effect_args = ['noiseprof', profile_path]
        self.build(input_filepath, None, extra_args=effect_args)

        return None

def
noiseprof
(
self
,
input_filepath
,
profile_path
)
:
if
os
.
path
.
isdir
(
profile_path
)
:
raise
ValueError
(
"profile_path {} is a directory."
.
format
(
profile_path
)
)
if
os
.
path
.
dirname
(
profile_path
)
==
''
and
profile_path
!=
''
:
_abs_profile_path
=
os
.
path
.
join
(
os
.
getcwd
(
)
,
profile_path
)
else
:
_abs_profile_path
=
profile_path
if
not
os
.
access
(
os
.
path
.
dirname
(
_abs_profile_path
)
,
os
.
W_OK
)
:
raise
IOError
(
"profile_path {} is not writeable."
.
format
(
_abs_profile_path
)
)
effect_args
=
[
'noiseprof'
,
profile_path
]
self
.
build
(
input_filepath
,
,
extra_args
=
effect_args
)
return

Calculate a profile of the audio for use in noise reduction . Running this command does not effect the Transformer effects chain . When this function is called the calculated noise profile file is saved to the profile_path .


def noisered(self, profile_path, amount=0.5):
        '''Reduce noise in the audio signal by profiling and filtering.
        This effect is moderately effective at removing consistent
        background noise such as hiss or hum.

        Parameters
        ----------
        profile_path : str
            Path to a noise profile file.
            This file can be generated using the `noiseprof` effect.
        amount : float, default=0.5
            How much noise should be removed is specified by amount. Should
            be between 0 and 1.  Higher numbers will remove more noise but
            present a greater likelihood  of  removing wanted  components  of
            the  audio  signal.

        See Also
        --------
        noiseprof

        '''

        if not os.path.exists(profile_path):
            raise IOError(
                "profile_path {} does not exist.".format(profile_path))

        if not is_number(amount) or amount < 0 or amount > 1:
            raise ValueError("amount must be a number between 0 and 1.")

        effect_args = [
            'noisered',
            profile_path,
            '{:f}'.format(amount)
        ]
        self.effects.extend(effect_args)
        self.effects_log.append('noisered')

        return self

Reduce noise in the audio signal by profiling and filtering . This effect is moderately effective at removing consistent background noise such as hiss or hum .


def norm(self, db_level=-3.0):
        '''Normalize an audio file to a particular db level.
        This behaves identically to the gain effect with normalize=True.

        Parameters
        ----------
        db_level : float, default=-3.0
            Output volume (db)

        See Also
        --------
        gain, loudness

        '''
        if not is_number(db_level):
            raise ValueError('db_level must be a number.')

        effect_args = [
            'norm',
            '{:f}'.format(db_level)
        ]
        self.effects.extend(effect_args)
        self.effects_log.append('norm')

        return self

def
norm
(
self
,
db_level
=
3.0
)
:
if
not
is_number
(
db_level
)
:
raise
ValueError
(
'db_level must be a number.'
)
effect_args
=
[
'norm'
,
'{:f}'
.
format
(
db_level
)
]
self
.
effects
.
extend
(
effect_args
)
self
.
effects_log
.
append
(
'norm'
)
return
self

Normalize an audio file to a particular db level . This behaves identically to the gain effect with normalize = True .


def oops(self):
        '''Out Of Phase Stereo effect. Mixes stereo to twin-mono where each
        mono channel contains the difference between the left and right stereo
        channels. This is sometimes known as the 'karaoke' effect as it often
        has the effect of removing most or all of the vocals from a recording.

        '''
        effect_args = ['oops']
        self.effects.extend(effect_args)
        self.effects_log.append('oops')

        return self

def oops ( self ) : effect_args = [ 'oops' ] self . effects . extend ( effect_args ) self . effects_log . append ( 'oops' ) return self

Out Of Phase Stereo effect . Mixes stereo to twin - mono where each mono channel contains the difference between the left and right stereo channels . This is sometimes known as the karaoke effect as it often has the effect of removing most or all of the vocals from a recording .


def overdrive(self, gain_db=20.0, colour=20.0):
        '''Apply non-linear distortion.

        Parameters
        ----------
        gain_db : float, default=20
            Controls the amount of distortion (dB).
        colour : float, default=20
            Controls the amount of even harmonic content in the output (dB).

        '''
        if not is_number(gain_db):
            raise ValueError('db_level must be a number.')

        if not is_number(colour):
            raise ValueError('colour must be a number.')

        effect_args = [
            'overdrive',
            '{:f}'.format(gain_db),
            '{:f}'.format(colour)
        ]
        self.effects.extend(effect_args)
        self.effects_log.append('overdrive')

        return self

def
overdrive
(
self
,
gain_db
=
20.0
,
colour
=
20.0
)
:
if
not
is_number
(
gain_db
)
:
raise
ValueError
(
'db_level must be a number.'
)
if
not
is_number
(
colour
)
:
raise
ValueError
(
'colour must be a number.'
)
effect_args
=
[
'overdrive'
,
'{:f}'
.
format
(
gain_db
)
,
'{:f}'
.
format
(
colour
)
]
self
.
effects
.
extend
(
effect_args
)
self
.
effects_log
.
append
(
'overdrive'
)
return
self


def pad(self, start_duration=0.0, end_duration=0.0):
        '''Add silence to the beginning or end of a file.
        Calling this with the default arguments has no effect.

        Parameters
        ----------
        start_duration : float
            Number of seconds of silence to add to beginning.
        end_duration : float
            Number of seconds of silence to add to end.

        See Also
        --------
        delay

        '''
        if not is_number(start_duration) or start_duration < 0:
            raise ValueError("Start duration must be a positive number.")

        if not is_number(end_duration) or end_duration < 0:
            raise ValueError("End duration must be positive.")

        effect_args = [
            'pad',
            '{:f}'.format(start_duration),
            '{:f}'.format(end_duration)
        ]
        self.effects.extend(effect_args)
        self.effects_log.append('pad')

        return self

Add silence to the beginning or end of a file . Calling this with the default arguments has no effect .


def phaser(self, gain_in=0.8, gain_out=0.74, delay=3, decay=0.4, speed=0.5,
               modulation_shape='sinusoidal'):
        '''Apply a phasing effect to the audio.

        Parameters
        ----------
        gain_in : float, default=0.8
            Input volume between 0 and 1
        gain_out: float, default=0.74
            Output volume between 0 and 1
        delay : float, default=3
            Delay in miliseconds between 0 and 5
        decay : float, default=0.4
            Decay relative to gain_in, between 0.1 and 0.5.
        speed : float, default=0.5
            Modulation speed in Hz, between 0.1 and 2
        modulation_shape : str, defaul='sinusoidal'
            Modulation shpae. One of 'sinusoidal' or 'triangular'

        See Also
        --------
        flanger, tremolo
        '''
        if not is_number(gain_in) or gain_in <= 0 or gain_in > 1:
            raise ValueError("gain_in must be a number between 0 and 1.")

        if not is_number(gain_out) or gain_out <= 0 or gain_out > 1:
            raise ValueError("gain_out must be a number between 0 and 1.")

        if not is_number(delay) or delay <= 0 or delay > 5:
            raise ValueError("delay must be a positive number.")

        if not is_number(decay) or decay < 0.1 or decay > 0.5:
            raise ValueError("decay must be a number between 0.1 and 0.5.")

        if not is_number(speed) or speed < 0.1 or speed > 2:
            raise ValueError("speed must be a positive number.")

        if modulation_shape not in ['sinusoidal', 'triangular']:
            raise ValueError(
                "modulation_shape must be one of 'sinusoidal', 'triangular'."
            )

        effect_args = [
            'phaser',
            '{:f}'.format(gain_in),
            '{:f}'.format(gain_out),
            '{:f}'.format(delay),
            '{:f}'.format(decay),
            '{:f}'.format(speed)
        ]

        if modulation_shape == 'sinusoidal':
            effect_args.append('-s')
        elif modulation_shape == 'triangular':
            effect_args.append('-t')

        self.effects.extend(effect_args)
        self.effects_log.append('phaser')

        return self


def pitch(self, n_semitones, quick=False):
        '''Pitch shift the audio without changing the tempo.

        This effect uses the WSOLA algorithm. The audio is chopped up into
        segments which are then shifted in the time domain and overlapped
        (cross-faded) at points where their waveforms are most similar as
        determined by measurement of least squares.

        Parameters
        ----------
        n_semitones : float
            The number of semitones to shift. Can be positive or negative.
        quick : bool, default=False
            If True, this effect will run faster but with lower sound quality.

        See Also
        --------
        bend, speed, tempo

        '''
        if not is_number(n_semitones):
            raise ValueError("n_semitones must be a positive number")

        if n_semitones < -12 or n_semitones > 12:
            logger.warning(
                "Using an extreme pitch shift. "
                "Quality of results will be poor"
            )

        if not isinstance(quick, bool):
            raise ValueError("quick must be a boolean.")

        effect_args = ['pitch']

        if quick:
            effect_args.append('-q')

        effect_args.append('{:f}'.format(n_semitones * 100.))

        self.effects.extend(effect_args)
        self.effects_log.append('pitch')

        return self

def
pitch
(
self
,
n_semitones
,
quick
=
False
)
:
if
not
is_number
(
n_semitones
)
:
raise
ValueError
(
"n_semitones must be a positive number"
)
if
n_semitones
<
12
or
n_semitones
>
12
:
logger
.
warning
(
"Using an extreme pitch shift. "
"Quality of results will be poor"
)
if
not
isinstance
(
quick
,
bool
)
:
raise
ValueError
(
"quick must be a boolean."
)
effect_args
=
[
'pitch'
]
if
quick
:
effect_args
.
append
(
'-q'
)
effect_args
.
append
(
'{:f}'
.
format
(
n_semitones
*
100.
)
)
self
.
effects
.
extend
(
effect_args
)
self
.
effects_log
.
append
(
'pitch'
)
return
self

Pitch shift the audio without changing the tempo .


def remix(self, remix_dictionary=None, num_output_channels=None):
        '''Remix the channels of an audio file.

        Note: volume options are not yet implemented

        Parameters
        ----------
        remix_dictionary : dict or None
            Dictionary mapping output channel to list of input channel(s).
            Empty lists indicate the corresponding output channel should be
            empty. If None, mixes all channels down to a single mono file.
        num_output_channels : int or None
            The number of channels in the output file. If None, the number of
            output channels is equal to the largest key in remix_dictionary.
            If remix_dictionary is None, this variable is ignored.

        Examples
        --------
        Remix a 4-channel input file. The output file will have
        input channel 2 in channel 1, a mixdown of input channels 1 an 3 in
        channel 2, an empty channel 3, and a copy of input channel 4 in
        channel 4.

        >>> import sox
        >>> tfm = sox.Transformer()
        >>> remix_dictionary = {1: [2], 2: [1, 3], 4: [4]}
        >>> tfm.remix(remix_dictionary)

        '''
        if not (isinstance(remix_dictionary, dict) or
                remix_dictionary is None):
            raise ValueError("remix_dictionary must be a dictionary or None.")

        if remix_dictionary is not None:

            if not all([isinstance(i, int) and i > 0 for i
                        in remix_dictionary.keys()]):
                raise ValueError(
                    "remix dictionary must have positive integer keys."
                )

            if not all([isinstance(v, list) for v
                        in remix_dictionary.values()]):
                raise ValueError("remix dictionary values must be lists.")

            for v_list in remix_dictionary.values():
                if not all([isinstance(v, int) and v > 0 for v in v_list]):
                    raise ValueError(
                        "elements of remix dictionary values must "
                        "be positive integers"
                    )

        if not ((isinstance(num_output_channels, int) and
                 num_output_channels > 0) or num_output_channels is None):
            raise ValueError(
                "num_output_channels must be a positive integer or None."
            )

        effect_args = ['remix']
        if remix_dictionary is None:
            effect_args.append('-')
        else:
            if num_output_channels is None:
                num_output_channels = max(remix_dictionary.keys())

            for channel in range(1, num_output_channels + 1):
                if channel in remix_dictionary.keys():
                    out_channel = ','.join(
                        [str(i) for i in remix_dictionary[channel]]
                    )
                else:
                    out_channel = '0'

                effect_args.append(out_channel)

        self.effects.extend(effect_args)
        self.effects_log.append('remix')

        return self


def repeat(self, count=1):
        '''Repeat the entire audio count times.

        Parameters
        ----------
        count : int, default=1
            The number of times to repeat the audio.

        '''
        if not isinstance(count, int) or count < 1:
            raise ValueError("count must be a postive integer.")

        effect_args = ['repeat', '{}'.format(count)]
        self.effects.extend(effect_args)
        self.effects_log.append('repeat')

def
repeat
(
self
,
count
=
1
)
:
if
not
isinstance
(
count
,
int
)
or
count
<
1
:
raise
ValueError
(
"count must be a postive integer."
)
effect_args
=
[
'repeat'
,
'{}'
.
format
(
count
)
]
self
.
effects
.
extend
(
effect_args
)
self
.
effects_log
.
append
(
'repeat'
)


def reverse(self):
        '''Reverse the audio completely
        '''
        effect_args = ['reverse']
        self.effects.extend(effect_args)
        self.effects_log.append('reverse')

        return self

def reverse ( self ) : effect_args = [ 'reverse' ] self . effects . extend ( effect_args ) self . effects_log . append ( 'reverse' ) return self


def silence(self, location=0, silence_threshold=0.1,
                min_silence_duration=0.1, buffer_around_silence=False):
        '''Removes silent regions from an audio file.

        Parameters
        ----------
        location : int, default=0
            Where to remove silence. One of:
             * 0 to remove silence throughout the file (default),
             * 1 to remove silence from the beginning,
             * -1 to remove silence from the end,
        silence_threshold : float, default=0.1
            Silence threshold as percentage of maximum sample amplitude.
            Must be between 0 and 100.
        min_silence_duration : float, default=0.1
            The minimum ammount of time in seconds required for a region to be
            considered non-silent.
        buffer_around_silence : bool, default=False
            If True, leaves a buffer of min_silence_duration around removed
            silent regions.

        See Also
        --------
        vad

        '''
        if location not in [-1, 0, 1]:
            raise ValueError("location must be one of -1, 0, 1.")

        if not is_number(silence_threshold) or silence_threshold < 0:
            raise ValueError(
                "silence_threshold must be a number between 0 and 100"
            )
        elif silence_threshold >= 100:
            raise ValueError(
                "silence_threshold must be a number between 0 and 100"
            )

        if not is_number(min_silence_duration) or min_silence_duration <= 0:
            raise ValueError(
                "min_silence_duration must be a positive number."
            )

        if not isinstance(buffer_around_silence, bool):
            raise ValueError("buffer_around_silence must be a boolean.")

        effect_args = []

        if location == -1:
            effect_args.append('reverse')

        if buffer_around_silence:
            effect_args.extend(['silence', '-l'])
        else:
            effect_args.append('silence')

        effect_args.extend([
            '1',
            '{:f}'.format(min_silence_duration),
            '{:f}%'.format(silence_threshold)
        ])

        if location == 0:
            effect_args.extend([
                '-1',
                '{:f}'.format(min_silence_duration),
                '{:f}%'.format(silence_threshold)
            ])

        if location == -1:
            effect_args.append('reverse')

        self.effects.extend(effect_args)
        self.effects_log.append('silence')

        return self

Removes silent regions from an audio file .


def stat(self, input_filepath, scale=None, rms=False):
        '''Display time and frequency domain statistical information about the
        audio. Audio is passed unmodified through the SoX processing chain.

        Unlike other Transformer methods, this does not modify the transformer
        effects chain. Instead it computes statistics on the output file that
        would be created if the build command were invoked.

        Note: The file is downmixed to mono prior to computation.

        Parameters
        ----------
        input_filepath : str
            Path to input file to compute stats on.
        scale : float or None, default=None
            If not None, scales the input by the given scale factor.
        rms : bool, default=False
            If True, scales all values by the average rms amplitude.

        Returns
        -------
        stat_dict : dict
            Dictionary of statistics.

        See Also
        --------
        stats, power_spectrum, sox.file_info
        '''
        effect_args = ['channels', '1', 'stat']
        if scale is not None:
            if not is_number(scale) or scale <= 0:
                raise ValueError("scale must be a positive number.")
            effect_args.extend(['-s', '{:f}'.format(scale)])

        if rms:
            effect_args.append('-rms')

        _, _, stat_output = self.build(
            input_filepath, None, extra_args=effect_args, return_output=True
        )

        stat_dict = {}
        lines = stat_output.split('\n')
        for line in lines:
            split_line = line.split()
            if len(split_line) == 0:
                continue
            value = split_line[-1]
            key = ' '.join(split_line[:-1])
            stat_dict[key.strip(':')] = value

        return stat_dict

def
stat
(
self
,
input_filepath
,
scale
=
,
rms
=
False
)
:
effect_args
=
[
'channels'
,
'1'
,
'stat'
]
if
scale
is
not
:
if
not
is_number
(
scale
)
or
scale
<=
0
:
raise
ValueError
(
"scale must be a positive number."
)
effect_args
.
extend
(
[
'-s'
,
'{:f}'
.
format
(
scale
)
]
)
if
rms
:
effect_args
.
append
(
'-rms'
)
_
,
_
,
stat_output
=
self
.
build
(
input_filepath
,
,
extra_args
=
effect_args
,
return_output
=
True
)
stat_dict
=
{
}
lines
=
stat_output
.
split
(
'\n'
)
for
line
in
lines
:
split_line
=
line
.
split
(
)
if
len
(
split_line
)
==
0
:
continue
value
=
split_line
[
1
]
key
=
' '
.
join
(
split_line
[
:
1
]
)
stat_dict
[
key
.
strip
(
':'
)
]
=
value
return
stat_dict

Display time and frequency domain statistical information about the audio . Audio is passed unmodified through the SoX processing chain .


def stats(self, input_filepath):
        '''Display time domain statistical information about the audio
        channels. Audio is passed unmodified through the SoX processing chain.
        Statistics are calculated and displayed for each audio channel

        Unlike other Transformer methods, this does not modify the transformer
        effects chain. Instead it computes statistics on the output file that
        would be created if the build command were invoked.

        Note: The file is downmixed to mono prior to computation.

        Parameters
        ----------
        input_filepath : str
            Path to input file to compute stats on.

        Returns
        -------
        stats_dict : dict
            List of frequency (Hz), amplitude pairs.

        See Also
        --------
        stat, sox.file_info
        '''
        effect_args = ['channels', '1', 'stats']

        _, _, stats_output = self.build(
            input_filepath, None, extra_args=effect_args, return_output=True
        )

        stats_dict = {}
        lines = stats_output.split('\n')
        for line in lines:
            split_line = line.split()
            if len(split_line) == 0:
                continue
            value = split_line[-1]
            key = ' '.join(split_line[:-1])
            stats_dict[key] = value

        return stats_dict

def
stats
(
self
,
input_filepath
)
:
effect_args
=
[
'channels'
,
'1'
,
'stats'
]
_
,
_
,
stats_output
=
self
.
build
(
input_filepath
,
,
extra_args
=
effect_args
,
return_output
=
True
)
stats_dict
=
{
}
lines
=
stats_output
.
split
(
'\n'
)
for
line
in
lines
:
split_line
=
line
.
split
(
)
if
len
(
split_line
)
==
0
:
continue
value
=
split_line
[
1
]
key
=
' '
.
join
(
split_line
[
:
1
]
)
stats_dict
[
key
]
=
value
return
stats_dict

Display time domain statistical information about the audio channels . Audio is passed unmodified through the SoX processing chain . Statistics are calculated and displayed for each audio channel


def swap(self):
        '''Swap stereo channels. If the input is not stereo, pairs of channels
        are swapped, and a possible odd last channel passed through.

        E.g., for seven channels, the output order will be 2, 1, 4, 3, 6, 5, 7.

        See Also
        ----------
        remix

        '''
        effect_args = ['swap']
        self.effects.extend(effect_args)
        self.effects_log.append('swap')

        return self

def swap ( self ) : effect_args = [ 'swap' ] self . effects . extend ( effect_args ) self . effects_log . append ( 'swap' ) return self

Swap stereo channels . If the input is not stereo pairs of channels are swapped and a possible odd last channel passed through .


def tempo(self, factor, audio_type=None, quick=False):
        '''Time stretch audio without changing pitch.

        This effect uses the WSOLA algorithm. The audio is chopped up into
        segments which are then shifted in the time domain and overlapped
        (cross-faded) at points where their waveforms are most similar as
        determined by measurement of least squares.

        Parameters
        ----------
        factor : float
            The ratio of new tempo to the old tempo.
            For ex. 1.1 speeds up the tempo by 10%; 0.9 slows it down by 10%.
        audio_type : str
            Type of audio, which optimizes algorithm parameters. One of:
             * m : Music,
             * s : Speech,
             * l : Linear (useful when factor is close to 1),
        quick : bool, default=False
            If True, this effect will run faster but with lower sound quality.

        See Also
        --------
        stretch, speed, pitch

        '''
        if not is_number(factor) or factor <= 0:
            raise ValueError("factor must be a positive number")

        if factor < 0.5 or factor > 2:
            logger.warning(
                "Using an extreme time stretching factor. "
                "Quality of results will be poor"
            )

        if abs(factor - 1.0) <= 0.1:
            logger.warning(
                "For this stretch factor, "
                "the stretch effect has better performance."
            )

        if audio_type not in [None, 'm', 's', 'l']:
            raise ValueError(
                "audio_type must be one of None, 'm', 's', or 'l'."
            )

        if not isinstance(quick, bool):
            raise ValueError("quick must be a boolean.")

        effect_args = ['tempo']

        if quick:
            effect_args.append('-q')

        if audio_type is not None:
            effect_args.append('-{}'.format(audio_type))

        effect_args.append('{:f}'.format(factor))

        self.effects.extend(effect_args)
        self.effects_log.append('tempo')

        return self

Time stretch audio without changing pitch .


def trim(self, start_time, end_time=None):
        '''Excerpt a clip from an audio file, given the start timestamp and end timestamp of the clip within the file, expressed in seconds. If the end timestamp is set to `None` or left unspecified, it defaults to the duration of the audio file.

        Parameters
        ----------
        start_time : float
            Start time of the clip (seconds)
        end_time : float or None, default=None
            End time of the clip (seconds)

        '''
        if not is_number(start_time) or start_time < 0:
            raise ValueError("start_time must be a positive number.")

        effect_args = [
            'trim',
            '{:f}'.format(start_time)
        ]

        if end_time is not None:
            if not is_number(end_time) or end_time < 0:
                raise ValueError("end_time must be a positive number.")
            if start_time >= end_time:
                raise ValueError("start_time must be smaller than end_time.")

            effect_args.append('{:f}'.format(end_time - start_time))

        self.effects.extend(effect_args)
        self.effects_log.append('trim')

        return self

Excerpt a clip from an audio file given the start timestamp and end timestamp of the clip within the file expressed in seconds . If the end timestamp is set to None or left unspecified it defaults to the duration of the audio file .


def vad(self, location=1, normalize=True, activity_threshold=7.0,
            min_activity_duration=0.25, initial_search_buffer=1.0,
            max_gap=0.25, initial_pad=0.0):
        '''Voice Activity Detector. Attempts to trim silence and quiet
        background sounds from the ends of recordings of speech. The algorithm
        currently uses a simple cepstral power measurement to detect voice, so
        may be fooled by other things, especially music.

        The effect can trim only from the front of the audio, so in order to
        trim from the back, the reverse effect must also be used.

        Parameters
        ----------
        location : 1 or -1, default=1
            If 1, trims silence from the beginning
            If -1, trims silence from the end
        normalize : bool, default=True
            If true, normalizes audio before processing.
        activity_threshold : float, default=7.0
            The measurement level used to trigger activity detection. This may
            need to be cahnged depending on the noise level, signal level, and
            other characteristics of the input audio.
        min_activity_duration : float, default=0.25
            The time constant (in seconds) used to help ignore short bursts of
            sound.
        initial_search_buffer : float, default=1.0
            The amount of audio (in seconds) to search for quieter/shorter
            bursts of audio to include prior to the detected trigger point.
        max_gap : float, default=0.25
            The allowed gap (in seconds) between quiteter/shorter bursts of
            audio to include prior to the detected trigger point
        initial_pad : float, default=0.0
            The amount of audio (in seconds) to preserve before the trigger
            point and any found quieter/shorter bursts.

        See Also
        --------
        silence

        Examples
        --------
        >>> tfm = sox.Transformer()

        Remove silence from the beginning of speech

        >>> tfm.vad(initial_pad=0.3)

        Remove silence from the end of speech

        >>> tfm.vad(location=-1, initial_pad=0.2)

        '''
        if location not in [-1, 1]:
            raise ValueError("location must be -1 or 1.")
        if not isinstance(normalize, bool):
            raise ValueError("normalize muse be a boolean.")
        if not is_number(activity_threshold):
            raise ValueError("activity_threshold must be a number.")
        if not is_number(min_activity_duration) or min_activity_duration < 0:
            raise ValueError("min_activity_duration must be a positive number")
        if not is_number(initial_search_buffer) or initial_search_buffer < 0:
            raise ValueError("initial_search_buffer must be a positive number")
        if not is_number(max_gap) or max_gap < 0:
            raise ValueError("max_gap must be a positive number.")
        if not is_number(initial_pad) or initial_pad < 0:
            raise ValueError("initial_pad must be a positive number.")

        effect_args = []

        if normalize:
            effect_args.append('norm')

        if location == -1:
            effect_args.append('reverse')

        effect_args.extend([
            'vad',
            '-t', '{:f}'.format(activity_threshold),
            '-T', '{:f}'.format(min_activity_duration),
            '-s', '{:f}'.format(initial_search_buffer),
            '-g', '{:f}'.format(max_gap),
            '-p', '{:f}'.format(initial_pad)
        ])

        if location == -1:
            effect_args.append('reverse')

        self.effects.extend(effect_args)
        self.effects_log.append('vad')

        return self

Voice Activity Detector . Attempts to trim silence and quiet background sounds from the ends of recordings of speech . The algorithm currently uses a simple cepstral power measurement to detect voice so may be fooled by other things especially music .


def vol(self, gain, gain_type='amplitude', limiter_gain=None):
        '''Apply an amplification or an attenuation to the audio signal.

        Parameters
        ----------
        gain : float
            Interpreted according to the given `gain_type`.
            If `gain_type' = 'amplitude', `gain' is a positive amplitude ratio.
            If `gain_type' = 'power', `gain' is a power (voltage squared).
            If `gain_type' = 'db', `gain' is in decibels.
        gain_type : string, default='amplitude'
            Type of gain. One of:
                - 'amplitude'
                - 'power'
                - 'db'
        limiter_gain : float or None, default=None
            If specified, a limiter is invoked on peaks greater than
            `limiter_gain' to prevent clipping.
            `limiter_gain` should be a positive value much less than 1.

        See Also
        --------
        gain, compand

        '''
        if not is_number(gain):
            raise ValueError('gain must be a number.')
        if limiter_gain is not None:
            if (not is_number(limiter_gain) or
                    limiter_gain <= 0 or limiter_gain >= 1):
                raise ValueError(
                    'limiter gain must be a positive number less than 1'
                )
        if gain_type in ['amplitude', 'power'] and gain < 0:
            raise ValueError(
                "If gain_type = amplitude or power, gain must be positive."
            )

        effect_args = ['vol']

        effect_args.append('{:f}'.format(gain))

        if gain_type == 'amplitude':
            effect_args.append('amplitude')
        elif gain_type == 'power':
            effect_args.append('power')
        elif gain_type == 'db':
            effect_args.append('dB')
        else:
            raise ValueError('gain_type must be one of amplitude power or db')

        if limiter_gain is not None:
            if gain_type in ['amplitude', 'power'] and gain > 1:
                effect_args.append('{:f}'.format(limiter_gain))
            elif gain_type == 'db' and gain > 0:
                effect_args.append('{:f}'.format(limiter_gain))

        self.effects.extend(effect_args)
        self.effects_log.append('vol')

        return self

Apply an amplification or an attenuation to the audio signal .


def join(self, room):
        """Lets a user join a room on a specific Namespace."""
        self.socket.rooms.add(self._get_room_name(room))

def join ( self , room ) : self . socket . rooms . add ( self . _get_room_name ( room ) )

Lets a user join a room on a specific Namespace .


def leave(self, room):
        """Lets a user leave a room on a specific Namespace."""
        self.socket.rooms.remove(self._get_room_name(room))

def leave ( self , room ) : self . socket . rooms . remove ( self . _get_room_name ( room ) )

Lets a user leave a room on a specific Namespace .


def socketio_manage(environ, namespaces, request=None, error_handler=None,
                    json_loads=None, json_dumps=None):
    """Main SocketIO management function, call from within your Framework of
    choice's view.

    The ``environ`` variable is the WSGI ``environ``.  It is used to extract
    Socket object from the underlying server (as the 'socketio' key), and will
    be attached to both the ``Socket`` and ``Namespace`` objects.

    The ``namespaces`` parameter is a dictionary of the namespace string
    representation as key, and the BaseNamespace namespace class descendant as
    a value.  The empty string ('') namespace is the global namespace.  You can
    use Socket.GLOBAL_NS to be more explicit. So it would look like:

    .. code-block:: python

      namespaces={'': GlobalNamespace,
                  '/chat': ChatNamespace}

    The ``request`` object is not required, but will probably be useful to pass
    framework-specific things into your Socket and Namespace functions. It will
    simply be attached to the Socket and Namespace object (accessible through
    ``self.request`` in both cases), and it is not accessed in any case by the
    ``gevent-socketio`` library.

    Pass in an ``error_handler`` if you want to override the default
    error_handler (which is :func:`socketio.virtsocket.default_error_handler`.
    The callable you pass in should have the same signature as the default
    error handler.

    The ``json_loads`` and ``json_dumps`` are overrides for the default
    ``json.loads`` and ``json.dumps`` function calls.  Override these at
    the top-most level here.  This will affect all sockets created by this
    socketio manager, and all namespaces inside.

    This function will block the current "view" or "controller" in your
    framework to do the recv/send on the socket, and dispatch incoming messages
    to your namespaces.

    This is a simple example using Pyramid:

    .. code-block:: python

      def my_view(request):
          socketio_manage(request.environ, {'': GlobalNamespace}, request)

    NOTE: You must understand that this function is going to be called
    *only once* per socket opening, *even though* you are using a long
    polling mechanism.  The subsequent calls (for long polling) will
    be hooked directly at the server-level, to interact with the
    active ``Socket`` instance.  This means you will *not* get access
    to the future ``request`` or ``environ`` objects.  This is of
    particular importance regarding sessions (like Beaker).  The
    session will be opened once at the opening of the Socket, and not
    closed until the socket is closed.  You are responsible for
    opening and closing the cookie-based session yourself if you want
    to keep its data in sync with the rest of your GET/POST calls.
    """
    socket = environ['socketio']
    socket._set_environ(environ)
    socket._set_namespaces(namespaces)

    if request:
        socket._set_request(request)

    if error_handler:
        socket._set_error_handler(error_handler)

    if json_loads:
        socket._set_json_loads(json_loads)
    if json_dumps:
        socket._set_json_dumps(json_dumps)

    receiver_loop = socket._spawn_receiver_loop()

    gevent.joinall([receiver_loop])

    # TODO: double check, what happens to the WSGI request here ? it vanishes ?
    return

Main SocketIO management function call from within your Framework of choice s view .


def _save_ack_callback(self, msgid, callback):
        """Keep a reference of the callback on this socket."""
        if msgid in self.ack_callbacks:
            return False
        self.ack_callbacks[msgid] = callback

def _save_ack_callback ( self , msgid , callback ) : if msgid in self . ack_callbacks : return False self . ack_callbacks [ msgid ] = callback

Keep a reference of the callback on this socket .


def _pop_ack_callback(self, msgid):
        """Fetch the callback for a given msgid, if it exists, otherwise,
        return None"""
        if msgid not in self.ack_callbacks:
            return None
        return self.ack_callbacks.pop(msgid)

def _pop_ack_callback ( self , msgid ) : if msgid not in self . ack_callbacks : return None return self . ack_callbacks . pop ( msgid )

Fetch the callback for a given msgid if it exists otherwise return None


def get_multiple_client_msgs(self, **kwargs):
        """Get multiple messages, in case we're going through the various
        XHR-polling methods, on which we can pack more than one message if the
        rate is high, and encode the payload for the HTTP channel."""
        client_queue = self.client_queue
        msgs = [client_queue.get(**kwargs)]
        while client_queue.qsize():
            msgs.append(client_queue.get())
        return msgs

def get_multiple_client_msgs ( self , * * kwargs ) : client_queue = self . client_queue msgs = [ client_queue . get ( * * kwargs ) ] while client_queue . qsize ( ) : msgs . append ( client_queue . get ( ) ) return msgs

Get multiple messages in case we re going through the various XHR - polling methods on which we can pack more than one message if the rate is high and encode the payload for the HTTP channel .


def remove_namespace(self, namespace):
        """This removes a Namespace object from the socket.

        This is usually called by
        :meth:`~socketio.namespace.BaseNamespace.disconnect`.

        """
        if namespace in self.active_ns:
            del self.active_ns[namespace]

        if len(self.active_ns) == 0 and self.connected:
            self.kill(detach=True)

def remove_namespace ( self , namespace ) : if namespace in self . active_ns : del self . active_ns [ namespace ] if len ( self . active_ns ) == 0 and self . connected : self . kill ( detach = True )

This removes a Namespace object from the socket .


def send_packet(self, pkt):
        """Low-level interface to queue a packet on the wire (encoded as wire
        protocol"""
        self.put_client_msg(packet.encode(pkt, self.json_dumps))

def send_packet ( self , pkt ) : self . put_client_msg ( packet . encode ( pkt , self . json_dumps ) )

Low - level interface to queue a packet on the wire ( encoded as wire protocol


def spawn(self, fn, *args, **kwargs):
        """Spawn a new Greenlet, attached to this Socket instance.

        It will be monitored by the "watcher" method
        """

        log.debug("Spawning sub-Socket Greenlet: %s" % fn.__name__)
        job = gevent.spawn(fn, *args, **kwargs)
        self.jobs.append(job)
        return job

def
spawn
(
self
,
fn
,
*
args
,
*
*
kwargs
)
:
log
.
debug
(
"Spawning sub-Socket Greenlet: %s"
%
fn
.
__name__
)
job
=
gevent
.
spawn
(
fn
,
*
args
,
*
*
kwargs
)
self
.
jobs
.
append
(
job
)
return
job

Spawn a new Greenlet attached to this Socket instance .


def _receiver_loop(self):
        """This is the loop that takes messages from the queue for the server
        to consume, decodes them and dispatches them.

        It is the main loop for a socket.  We join on this process before
        returning control to the web framework.

        This process is not tracked by the socket itself, it is not going
        to be killed by the ``gevent.killall(socket.jobs)``, so it must
        exit gracefully itself.
        """

        while True:
            rawdata = self.get_server_msg()

            if not rawdata:
                continue  # or close the connection ?
            try:
                pkt = packet.decode(rawdata, self.json_loads)
            except (ValueError, KeyError, Exception) as e:
                self.error('invalid_packet',
                    "There was a decoding error when dealing with packet "
                    "with event: %s... (%s)" % (rawdata[:20], e))
                continue

            if pkt['type'] == 'heartbeat':
                # This is already dealth with in put_server_msg() when
                # any incoming raw data arrives.
                continue

            if pkt['type'] == 'disconnect' and pkt['endpoint'] == '':
                # On global namespace, we kill everything.
                self.kill(detach=True)
                continue

            endpoint = pkt['endpoint']

            if endpoint not in self.namespaces:
                self.error("no_such_namespace",
                    "The endpoint you tried to connect to "
                    "doesn't exist: %s" % endpoint, endpoint=endpoint)
                continue
            elif endpoint in self.active_ns:
                pkt_ns = self.active_ns[endpoint]
            else:
                new_ns_class = self.namespaces[endpoint]
                pkt_ns = new_ns_class(self.environ, endpoint,
                                        request=self.request)
                # This calls initialize() on all the classes and mixins, etc..
                # in the order of the MRO
                for cls in type(pkt_ns).__mro__:
                    if hasattr(cls, 'initialize'):
                        cls.initialize(pkt_ns)  # use this instead of __init__,
                                                # for less confusion

                self.active_ns[endpoint] = pkt_ns

            retval = pkt_ns.process_packet(pkt)

            # Has the client requested an 'ack' with the reply parameters ?
            if pkt.get('ack') == "data" and pkt.get('id'):
                if type(retval) is tuple:
                    args = list(retval)
                else:
                    args = [retval]
                returning_ack = dict(type='ack', ackId=pkt['id'],
                                     args=args,
                                     endpoint=pkt.get('endpoint', ''))
                self.send_packet(returning_ack)

            # Now, are we still connected ?
            if not self.connected:
                self.kill(detach=True)  # ?? what,s the best clean-up
                                        # when its not a
                                        # user-initiated disconnect
                return

This is the loop that takes messages from the queue for the server to consume decodes them and dispatches them .


def _watcher(self):
        """Watch out if we've been disconnected, in that case, kill
        all the jobs.

        """
        while True:
            gevent.sleep(1.0)
            if not self.connected:
                for ns_name, ns in list(six.iteritems(self.active_ns)):
                    ns.recv_disconnect()
                # Killing Socket-level jobs
                gevent.killall(self.jobs)
                break

def
_watcher
(
self
)
:
while
True
:
gevent
.
sleep
(
1.0
)
if
not
self
.
connected
:
for
ns_name
,
ns
in
list
(
six
.
iteritems
(
self
.
active_ns
)
)
:
ns
.
recv_disconnect
(
)
# Killing Socket-level jobs
gevent
.
killall
(
self
.
jobs
)
break

Watch out if we ve been disconnected in that case kill all the jobs .


def _heartbeat(self):
        """Start the heartbeat Greenlet to check connection health."""
        interval = self.config['heartbeat_interval']
        while self.connected:
            gevent.sleep(interval)
            # TODO: this process could use a timeout object like the disconnect
            #       timeout thing, and ONLY send packets when none are sent!
            #       We would do that by calling timeout.set() for a "sending"
            #       timeout.  If we're sending 100 messages a second, there is
            #       no need to push some heartbeats in there also.
            self.put_client_msg("2::")

Start the heartbeat Greenlet to check connection health .


def _spawn_heartbeat(self):
        """This functions returns a list of jobs"""
        self.spawn(self._heartbeat)
        self.spawn(self._heartbeat_timeout)

def _spawn_heartbeat ( self ) : self . spawn ( self . _heartbeat ) self . spawn ( self . _heartbeat_timeout )


def encode(data, json_dumps=default_json_dumps):
    """
    Encode an attribute dict into a byte string.
    """
    payload = ''
    msg = str(MSG_TYPES[data['type']])

    if msg in ['0', '1']:
        # '1::' [path] [query]
        msg += '::' + data['endpoint']
        if 'qs' in data and data['qs'] != '':
            msg += ':' + data['qs']

    elif msg == '2':
        # heartbeat
        msg += '::'

    elif msg in ['3', '4', '5']:
        # '3:' [id ('+')] ':' [endpoint] ':' [data]
        # '4:' [id ('+')] ':' [endpoint] ':' [json]
        # '5:' [id ('+')] ':' [endpoint] ':' [json encoded event]
        # The message id is an incremental integer, required for ACKs.
        # If the message id is followed by a +, the ACK is not handled by
        # socket.io, but by the user instead.
        if msg == '3':
            payload = data['data']
        if msg == '4':
            payload = json_dumps(data['data'])
        if msg == '5':
            d = {}
            d['name'] = data['name']
            if 'args' in data and data['args'] != []:
                d['args'] = data['args']
            payload = json_dumps(d)
        if 'id' in data:
            msg += ':' + str(data['id'])
            if data['ack'] == 'data':
                msg += '+'
            msg += ':'
        else:
            msg += '::'
        if 'endpoint' not in data:
            data['endpoint'] = ''
        if payload != '':
            msg += data['endpoint'] + ':' + payload
        else:
            msg += data['endpoint']

    elif msg == '6':
        # '6:::' [id] '+' [data]
        msg += '::' + data.get('endpoint', '') + ':' + str(data['ackId'])
        if 'args' in data and data['args'] != []:
            msg += '+' + json_dumps(data['args'])

    elif msg == '7':
        # '7::' [endpoint] ':' [reason] '+' [advice]
        msg += ':::'
        if 'reason' in data and data['reason'] != '':
            msg += str(ERROR_REASONS[data['reason']])
        if 'advice' in data and data['advice'] != '':
            msg += '+' + str(ERROR_ADVICES[data['advice']])
        msg += data['endpoint']

    # NoOp, used to close a poll after the polling duration time
    elif msg == '8':
        msg += '::'

    return msg

Encode an attribute dict into a byte string .


def decode(rawstr, json_loads=default_json_loads):
    """
    Decode a rawstr packet arriving from the socket into a dict.
    """
    decoded_msg = {}
    try:
        # Handle decoding in Python<3.
        rawstr = rawstr.decode('utf-8')
    except AttributeError:
        pass
    split_data = rawstr.split(":", 3)
    msg_type = split_data[0]
    msg_id = split_data[1]
    endpoint = split_data[2]

    data = ''

    if msg_id != '':
        if "+" in msg_id:
            msg_id = msg_id.split('+')[0]
            decoded_msg['id'] = int(msg_id)
            decoded_msg['ack'] = 'data'
        else:
            decoded_msg['id'] = int(msg_id)
            decoded_msg['ack'] = True

    # common to every message
    msg_type_id = int(msg_type)
    if msg_type_id in MSG_VALUES:
        decoded_msg['type'] = MSG_VALUES[int(msg_type)]
    else:
        raise Exception("Unknown message type: %s" % msg_type)

    decoded_msg['endpoint'] = endpoint

    if len(split_data) > 3:
        data = split_data[3]

    if msg_type == "0":  # disconnect
        pass

    elif msg_type == "1":  # connect
        decoded_msg['qs'] = data

    elif msg_type == "2":  # heartbeat
        pass

    elif msg_type == "3":  # message
        decoded_msg['data'] = data

    elif msg_type == "4":  # json msg
        decoded_msg['data'] = json_loads(data)

    elif msg_type == "5":  # event
        try:
            data = json_loads(data)
        except ValueError:
            print("Invalid JSON event message", data)
            decoded_msg['args'] = []
        else:
            decoded_msg['name'] = data.pop('name')
            if 'args' in data:
                decoded_msg['args'] = data['args']
            else:
                decoded_msg['args'] = []

    elif msg_type == "6":  # ack
        if '+' in data:
            ackId, data = data.split('+')
            decoded_msg['ackId'] = int(ackId)
            decoded_msg['args'] = json_loads(data)
        else:
            decoded_msg['ackId'] = int(data)
            decoded_msg['args'] = []

    elif msg_type == "7":  # error
        if '+' in data:
            reason, advice = data.split('+')
            decoded_msg['reason'] = REASONS_VALUES[int(reason)]
            decoded_msg['advice'] = ADVICES_VALUES[int(advice)]
        else:
            decoded_msg['advice'] = ''
            if data != '':
                decoded_msg['reason'] = REASONS_VALUES[int(data)]
            else:
                decoded_msg['reason'] = ''

    elif msg_type == "8":  # noop
        pass

    return decoded_msg

def
decode
(
rawstr
,
json_loads
=
default_json_loads
)
:
decoded_msg
=
{
}
try
:
# Handle decoding in Python<3.
rawstr
=
rawstr
.
decode
(
'utf-8'
)
except
AttributeError
:
pass
split_data
=
rawstr
.
split
(
":"
,
3
)
msg_type
=
split_data
[
0
]
msg_id
=
split_data
[
1
]
endpoint
=
split_data
[
2
]
data
=
''
if
msg_id
!=
''
:
if
"+"
in
msg_id
:
msg_id
=
msg_id
.
split
(
'+'
)
[
0
]
decoded_msg
[
'id'
]
=
int
(
msg_id
)
decoded_msg
[
'ack'
]
=
'data'
else
:
decoded_msg
[
'id'
]
=
int
(
msg_id
)
decoded_msg
[
'ack'
]
=
True
# common to every message
msg_type_id
=
int
(
msg_type
)
if
msg_type_id
in
MSG_VALUES
:
decoded_msg
[
'type'
]
=
MSG_VALUES
[
int
(
msg_type
)
]
else
:
raise
Exception
(
"Unknown message type: %s"
%
msg_type
)
decoded_msg
[
'endpoint'
]
=
endpoint
if
len
(
split_data
)
>
3
:
data
=
split_data
[
3
]
if
msg_type
==
"0"
:
# disconnect
pass
elif
msg_type
==
"1"
:
# connect
decoded_msg
[
'qs'
]
=
data
elif
msg_type
==
"2"
:
# heartbeat
pass
elif
msg_type
==
"3"
:
# message
decoded_msg
[
'data'
]
=
data
elif
msg_type
==
"4"
:
# json msg
decoded_msg
[
'data'
]
=
json_loads
(
data
)
elif
msg_type
==
"5"
:
# event
try
:
data
=
json_loads
(
data
)
except
ValueError
:
print
(
"Invalid JSON event message"
,
data
)
decoded_msg
[
'args'
]
=
[
]
else
:
decoded_msg
[
'name'
]
=
data
.
pop
(
'name'
)
if
'args'
in
data
:
decoded_msg
[
'args'
]
=
data
[
'args'
]
else
:
decoded_msg
[
'args'
]
=
[
]
elif
msg_type
==
"6"
:
# ack
if
'+'
in
data
:
ackId
,
data
=
data
.
split
(
'+'
)
decoded_msg
[
'ackId'
]
=
int
(
ackId
)
decoded_msg
[
'args'
]
=
json_loads
(
data
)
else
:
decoded_msg
[
'ackId'
]
=
int
(
data
)
decoded_msg
[
'args'
]
=
[
]
elif
msg_type
==
"7"
:
# error
if
'+'
in
data
:
reason
,
advice
=
data
.
split
(
'+'
)
decoded_msg
[
'reason'
]
=
REASONS_VALUES
[
int
(
reason
)
]
decoded_msg
[
'advice'
]
=
ADVICES_VALUES
[
int
(
advice
)
]
else
:
decoded_msg
[
'advice'
]
=
''
if
data
!=
''
:
decoded_msg
[
'reason'
]
=
REASONS_VALUES
[
int
(
data
)
]
else
:
decoded_msg
[
'reason'
]
=
''
elif
msg_type
==
"8"
:
# noop
pass
return
decoded_msg

Decode a rawstr packet arriving from the socket into a dict .


def process_event(self, packet):
        """This function dispatches ``event`` messages to the correct
        functions. You should override this method only if you are not
        satisfied with the automatic dispatching to
        ``on_``-prefixed methods.  You could then implement your own dispatch.
        See the source code for inspiration.

        There are two ways to deal with callbacks from the client side
        (meaning, the browser has a callback waiting for data that this
        server will be sending back):

        The first one is simply to return an object.  If the incoming
        packet requested has an 'ack' field set, meaning the browser is
        waiting for callback data, it will automatically be packaged
        and sent, associated with the 'ackId' from the browser. The
        return value must be a *sequence* of elements, that will be
        mapped to the positional parameters of the callback function
        on the browser side.

        If you want to *know* that you're dealing with a packet
        that requires a return value, you can do those things manually
        by inspecting the ``ack`` and ``id`` keys from the ``packet``
        object.  Your callback will behave specially if the name of
        the argument to your method is ``packet``.  It will fill it
        with the unprocessed ``packet`` object for your inspection,
        like this:

        .. code-block:: python

          def on_my_callback(self, packet):
              if 'ack' in packet:
                  self.emit('go_back', 'param1', id=packet['id'])
        """
        args = packet['args']
        name = packet['name']
        if not allowed_event_name_regex.match(name):
            self.error("unallowed_event_name",
                       "name must only contains alpha numerical characters")
            return

        method_name = 'on_' + name.replace(' ', '_')
        # This means the args, passed as a list, will be expanded to
        # the method arg and if you passed a dict, it will be a dict
        # as the first parameter.

        return self.call_method_with_acl(method_name, packet, *args)

This function dispatches event messages to the correct functions . You should override this method only if you are not satisfied with the automatic dispatching to on_ - prefixed methods . You could then implement your own dispatch . See the source code for inspiration .


def call_method_with_acl(self, method_name, packet, *args):
        """You should always use this function to call the methods,
        as it checks if the user is allowed according to the ACLs.

        If you override :meth:`process_packet` or
        :meth:`process_event`, you should definitely want to use this
        instead of ``getattr(self, 'my_method')()``
        """
        if not self.is_method_allowed(method_name):
            self.error('method_access_denied',
                       'You do not have access to method "%s"' % method_name)
            return

        return self.call_method(method_name, packet, *args)

def
call_method_with_acl
(
self
,
method_name
,
packet
,
*
args
)
:
if
not
self
.
is_method_allowed
(
method_name
)
:
self
.
error
(
'method_access_denied'
,
'You do not have access to method "%s"'
%
method_name
)
return
return
self
.
call_method
(
method_name
,
packet
,
*
args
)

You should always use this function to call the methods as it checks if the user is allowed according to the ACLs .


def error(self, error_name, error_message, msg_id=None, quiet=False):
        """Use this to use the configured ``error_handler`` yield an
        error message to your application.

        :param error_name: is a short string, to associate messages to recovery
                           methods
        :param error_message: is some human-readable text, describing the error
        :param msg_id: is used to associate with a request
        :param quiet: specific to error_handlers. The default doesn't send a
                      message to the user, but shows a debug message on the
                      developer console.
        """
        self.socket.error(error_name, error_message, endpoint=self.ns_name,
                          msg_id=msg_id, quiet=quiet)

def error ( self , error_name , error_message , msg_id = None , quiet = False ) : self . socket . error ( error_name , error_message , endpoint = self . ns_name , msg_id = msg_id , quiet = quiet )

Use this to use the configured error_handler yield an error message to your application .


def send(self, message, json=False, callback=None):
        """Use send to send a simple string message.

        If ``json`` is True, the message will be encoded as a JSON object
        on the wire, and decoded on the other side.

        This is mostly for backwards compatibility.  ``emit()`` is more fun.

        :param callback: This is a callback function that will be
                         called automatically by the client upon
                         reception.  It does not verify that the
                         listener over there was completed with
                         success.  It just tells you that the browser
                         got a hold of the packet.
        :type callback: callable
        """
        pkt = dict(type="message", data=message, endpoint=self.ns_name)
        if json:
            pkt['type'] = "json"

        if callback:
            # By passing ack=True, we use the old behavior of being returned
            # an 'ack' packet, automatically triggered by the client-side
            # with no user-code being run.  The emit() version of the
            # callback is more useful I think :)  So migrate your code.
            pkt['ack'] = True
            pkt['id'] = msgid = self.socket._get_next_msgid()
            self.socket._save_ack_callback(msgid, callback)

        self.socket.send_packet(pkt)

Use send to send a simple string message .


def emit(self, event, *args, **kwargs):
        """Use this to send a structured event, with a name and arguments, to
        the client.

        By default, it uses this namespace's endpoint. You can send messages on
        other endpoints with something like:

            ``self.socket['/other_endpoint'].emit()``.

        However, it is possible that the ``'/other_endpoint'`` was not
        initialized yet, and that would yield a ``KeyError``.

        The only supported ``kwargs`` is ``callback``.  All other parameters
        must be passed positionally.

        :param event: The name of the event to trigger on the other end.
        :param callback: Pass in the callback keyword argument to define a
                         call-back that will be called when the client acks.

                         This callback is slightly different from the one from
                         ``send()``, as this callback will receive parameters
                         from the explicit call of the ``ack()`` function
                         passed to the listener on the client side.

                         The remote listener will need to explicitly ack (by
                         calling its last argument, a function which is
                         usually called 'ack') with some parameters indicating
                         success or error.  The 'ack' packet coming back here
                         will then trigger the callback function with the
                         returned values.
        :type callback: callable
        """
        callback = kwargs.pop('callback', None)

        if kwargs:
            raise ValueError(
                "emit() only supports positional argument, to stay "
                "compatible with the Socket.IO protocol. You can "
                "however pass in a dictionary as the first argument")
        pkt = dict(type="event", name=event, args=args,
                   endpoint=self.ns_name)

        if callback:
            # By passing 'data', we indicate that we *want* an explicit ack
            # by the client code, not an automatic as with send().
            pkt['ack'] = 'data'
            pkt['id'] = msgid = self.socket._get_next_msgid()
            self.socket._save_ack_callback(msgid, callback)

        self.socket.send_packet(pkt)

Use this to send a structured event with a name and arguments to the client .


def spawn(self, fn, *args, **kwargs):
        """Spawn a new process, attached to this Namespace.

        It will be monitored by the "watcher" process in the Socket. If the
        socket disconnects, all these greenlets are going to be killed, after
        calling BaseNamespace.disconnect()

        This method uses the ``exception_handler_decorator``.  See
        Namespace documentation for more information.

        """
        # self.log.debug("Spawning sub-Namespace Greenlet: %s" % fn.__name__)
        if hasattr(self, 'exception_handler_decorator'):
            fn = self.exception_handler_decorator(fn)
        new = gevent.spawn(fn, *args, **kwargs)
        self.jobs.append(new)
        return new

Spawn a new process attached to this Namespace .


def get_socket(self, sessid=''):
        """Return an existing or new client Socket."""

        socket = self.sockets.get(sessid)

        if sessid and not socket:
            return None  # you ask for a session that doesn't exist!
        if socket is None:
            socket = Socket(self, self.config)
            self.sockets[socket.sessid] = socket
        else:
            socket.incr_hits()

        return socket

Return an existing or new client Socket .


def create():
    """
    Handles post from the "Add room" form on the homepage, and
    redirects to the new room.
    """
    name = request.form.get("name")
    if name:
        room, created = get_or_create(ChatRoom, name=name)
        return redirect(url_for('room', slug=room.slug))
    return redirect(url_for('rooms'))

def create ( ) : name = request . form . get ( "name" ) if name : room , created = get_or_create ( ChatRoom , name = name ) return redirect ( url_for ( 'room' , slug = room . slug ) ) return redirect ( url_for ( 'rooms' ) )

Handles post from the Add room form on the homepage and redirects to the new room .


def get_messages_payload(self, socket, timeout=None):
        """This will fetch the messages from the Socket's queue, and if
        there are many messes, pack multiple messages in one payload and return
        """
        try:
            msgs = socket.get_multiple_client_msgs(timeout=timeout)
            data = self.encode_payload(msgs)
        except Empty:
            data = ""
        return data

def get_messages_payload ( self , socket , timeout = None ) : try : msgs = socket . get_multiple_client_msgs ( timeout = timeout ) data = self . encode_payload ( msgs ) except Empty : data = "" return data

This will fetch the messages from the Socket s queue and if there are many messes pack multiple messages in one payload and return


def encode_payload(self, messages):
        """Encode list of messages. Expects messages to be unicode.

        ``messages`` - List of raw messages to encode, if necessary

        """
        if not messages or messages[0] is None:
            return ''

        if len(messages) == 1:
            return messages[0].encode('utf-8')

        payload = u''.join([(u'\ufffd%d\ufffd%s' % (len(p), p))
                            for p in messages if p is not None])
        # FIXME: why is it so that we must filter None from here ?  How
        #        is it even possible that a None gets in there ?

        return payload.encode('utf-8')

Encode list of messages . Expects messages to be unicode .


def write(self, data):
        """Just quote out stuff before sending it out"""
        args = parse_qs(self.handler.environ.get("QUERY_STRING"))
        if "i" in args:
            i = args["i"]
        else:
            i = "0"
        # TODO: don't we need to quote this data in here ?
        super(JSONPolling, self).write("io.j[%s]('%s');" % (i, data))


def broadcast_event(self, event, *args):
        """
        This is sent to all in the sockets in this particular Namespace,
        including itself.
        """
        pkt = dict(type="event",
                   name=event,
                   args=args,
                   endpoint=self.ns_name)

        for sessid, socket in six.iteritems(self.socket.server.sockets):
            socket.send_packet(pkt)

def broadcast_event ( self , event , * args ) : pkt = dict ( type = "event" , name = event , args = args , endpoint = self . ns_name ) for sessid , socket in six . iteritems ( self . socket . server . sockets ) : socket . send_packet ( pkt )

This is sent to all in the sockets in this particular Namespace including itself .


def add_parent(self, parent):
        """Add a parent to this role,
        and add role itself to the parent's children set.
        you should override this function if neccessary.

        Example::

            logged_user = RoleMixin('logged_user')
            student = RoleMixin('student')
            student.add_parent(logged_user)

        :param parent: Parent role to add in.
        """
        parent.children.add(self)
        self.parents.add(parent)

def add_parent ( self , parent ) : parent . children . add ( self ) self . parents . add ( parent )

Add a parent to this role and add role itself to the parent s children set . you should override this function if neccessary .


def allow(self, role, method, resource, with_children=True):
        """Add allowing rules.

        :param role: Role of this rule.
        :param method: Method to allow in rule, include GET, POST, PUT etc.
        :param resource: Resource also view function.
        :param with_children: Allow role's children in rule as well
                              if with_children is `True`
        """
        if with_children:
            for r in role.get_children():
                permission = (r.get_name(), method, resource)
                if permission not in self._allowed:
                    self._allowed.append(permission)
        if role == 'anonymous':
            permission = (role, method, resource)
        else:
            permission = (role.get_name(), method, resource)
        if permission not in self._allowed:
            self._allowed.append(permission)

def allow ( self , role , method , resource , with_children = True ) : if with_children : for r in role . get_children ( ) : permission = ( r . get_name ( ) , method , resource ) if permission not in self . _allowed : self . _allowed . append ( permission ) if role == 'anonymous' : permission = ( role , method , resource ) else : permission = ( role . get_name ( ) , method , resource ) if permission not in self . _allowed : self . _allowed . append ( permission )


def deny(self, role, method, resource, with_children=False):
        """Add denying rules.

        :param role: Role of this rule.
        :param method: Method to deny in rule, include GET, POST, PUT etc.
        :param resource: Resource also view function.
        :param with_children: Deny role's children in rule as well
                              if with_children is `True`
        """
        if with_children:
            for r in role.get_children():
                permission = (r.get_name(), method, resource)
                if permission not in self._denied:
                    self._denied.append(permission)
        permission = (role.get_name(), method, resource)
        if permission not in self._denied:
            self._denied.append(permission)

def deny ( self , role , method , resource , with_children = False ) : if with_children : for r in role . get_children ( ) : permission = ( r . get_name ( ) , method , resource ) if permission not in self . _denied : self . _denied . append ( permission ) permission = ( role . get_name ( ) , method , resource ) if permission not in self . _denied : self . _denied . append ( permission )


def exempt(self, resource):
        """Exempt a view function from being checked permission

        :param resource: The view function exempt from checking.
        """
        if resource not in self._exempt:
            self._exempt.append(resource)

def exempt ( self , resource ) : if resource not in self . _exempt : self . _exempt . append ( resource )


def is_allowed(self, role, method, resource):
        """Check whether role is allowed to access resource

        :param role: Role to be checked.
        :param method: Method to be checked.
        :param resource: View function to be checked.
        """
        return (role, method, resource) in self._allowed

def is_allowed ( self , role , method , resource ) : return ( role , method , resource ) in self . _allowed


def is_denied(self, role, method, resource):
        """Check wherther role is denied to access resource

        :param role: Role to be checked.
        :param method: Method to be checked.
        :param resource: View function to be checked.
        """
        return (role, method, resource) in self._denied

def is_denied ( self , role , method , resource ) : return ( role , method , resource ) in self . _denied


def allow(self, roles, methods, with_children=True):
        """This is a decorator function.

        You can allow roles to access the view func with it.

        An example::

            @app.route('/website/setting', methods=['GET', 'POST'])
            @rbac.allow(['administrator', 'super_user'], ['GET', 'POST'])
            def website_setting():
                return Response('Setting page.')

        :param roles: List, each name of roles. Please note that,
                      `anonymous` is refered to anonymous.
                      If you add `anonymous` to the rule,
                      everyone can access the resource,
                      unless you deny other roles.
        :param methods: List, each name of methods.
                        methods is valid in ['GET', 'POST', 'PUT', 'DELETE']
        :param with_children: Whether allow children of roles as well.
                              True by default.
        """
        def decorator(view_func):
            _methods = [m.upper() for m in methods]
            for r, m, v in itertools.product(roles, _methods, [view_func.__name__]):
                self.before_acl['allow'].append((r, m, v, with_children))
            return view_func
        return decorator

def allow ( self , roles , methods , with_children = True ) : def decorator ( view_func ) : _methods = [ m . upper ( ) for m in methods ] for r , m , v in itertools . product ( roles , _methods , [ view_func . __name__ ] ) : self . before_acl [ 'allow' ] . append ( ( r , m , v , with_children ) ) return view_func return decorator


def remove_binaries():
    """Remove all binary files in the adslib directory."""
    patterns = (
        "adslib/*.a",
        "adslib/*.o",
        "adslib/obj/*.o",
        "adslib/*.bin",
        "adslib/*.so",
    )

    for f in functools.reduce(operator.iconcat, [glob.glob(p) for p in patterns]):
        os.remove(f)

def remove_binaries ( ) : patterns = ( "adslib/*.a" , "adslib/*.o" , "adslib/obj/*.o" , "adslib/*.bin" , "adslib/*.so" , ) for f in functools . reduce ( operator . iconcat , [ glob . glob ( p ) for p in patterns ] ) : os . remove ( f )

Remove all binary files in the adslib directory .


def router_function(fn):
    # type: (Callable) -> Callable
    """Raise a runtime error if on Win32 systems.

    Decorator.

    Decorator for functions that interact with the router for the Linux
    implementation of the ADS library.

    Unlike the Windows implementation which uses a separate router daemon,
    the Linux library manages AMS routing in-process. As such, routing must be
    configured programatically via. the provided API. These endpoints are
    invalid on Win32 systems, so an exception will be raised.

    """

    @wraps(fn)
    def wrapper(*args, **kwargs):
        # type: (Any, Any) -> Callable
        if platform_is_windows():  # pragma: no cover, skipt Windows test
            raise RuntimeError(
                "Router interface is not available on Win32 systems.\n"
                "Configure AMS routes using the TwinCAT router service."
            )
        return fn(*args, **kwargs)

    return wrapper

Raise a runtime error if on Win32 systems .


def adsAddRoute(net_id, ip_address):
    # type: (SAmsNetId, str) -> None
    """Establish a new route in the AMS Router.

    :param pyads.structs.SAmsNetId net_id: net id of routing endpoint
    :param str ip_address: ip address of the routing endpoint

    """
    add_route = _adsDLL.AdsAddRoute
    add_route.restype = ctypes.c_long

    # Convert ip address to bytes (PY3) and get pointer.
    ip_address_p = ctypes.c_char_p(ip_address.encode("utf-8"))

    error_code = add_route(net_id, ip_address_p)

    if error_code:
        raise ADSError(error_code)

Establish a new route in the AMS Router .


def adsPortCloseEx(port):
    # type: (int) -> None
    """Close the connection to the TwinCAT message router."""
    port_close_ex = _adsDLL.AdsPortCloseEx
    port_close_ex.restype = ctypes.c_long
    error_code = port_close_ex(port)

    if error_code:
        raise ADSError(error_code)

def
adsPortCloseEx
(
port
)
:
# type: (int) -> None
port_close_ex
=
_adsDLL
.
AdsPortCloseEx
port_close_ex
.
restype
=
ctypes
.
c_long
error_code
=
port_close_ex
(
port
)
if
error_code
:
raise
ADSError
(
error_code
)

Close the connection to the TwinCAT message router .


def adsGetLocalAddressEx(port):
    # type: (int) -> AmsAddr
    """Return the local AMS-address and the port number.

    :rtype: pyads.structs.AmsAddr
    :return: AMS-address

    """
    get_local_address_ex = _adsDLL.AdsGetLocalAddressEx
    ams_address_struct = SAmsAddr()
    error_code = get_local_address_ex(port, ctypes.pointer(ams_address_struct))

    if error_code:
        raise ADSError(error_code)

    local_ams_address = AmsAddr()
    local_ams_address._ams_addr = ams_address_struct

    return local_ams_address

def
adsGetLocalAddressEx
(
port
)
:
# type: (int) -> AmsAddr
get_local_address_ex
=
_adsDLL
.
AdsGetLocalAddressEx
ams_address_struct
=
SAmsAddr
(
)
error_code
=
get_local_address_ex
(
port
,
ctypes
.
pointer
(
ams_address_struct
)
)
if
error_code
:
raise
ADSError
(
error_code
)
local_ams_address
=
AmsAddr
(
)
local_ams_address
.
_ams_addr
=
ams_address_struct
return
local_ams_address

Return the local AMS - address and the port number .


def adsSyncReadStateReqEx(port, address):
    # type: (int, AmsAddr) -> Tuple[int, int]
    """Read the current ADS-state and the machine-state.

    Read the current ADS-state and the machine-state from the
    ADS-server.

    :param pyads.structs.AmsAddr address: local or remote AmsAddr
    :rtype: (int, int)
    :return: ads_state, device_state

    """
    sync_read_state_request = _adsDLL.AdsSyncReadStateReqEx

    # C pointer to ams address struct
    ams_address_pointer = ctypes.pointer(address.amsAddrStruct())

    # Current ADS status and corresponding pointer
    ads_state = ctypes.c_int()
    ads_state_pointer = ctypes.pointer(ads_state)

    # Current device status and corresponding pointer
    device_state = ctypes.c_int()
    device_state_pointer = ctypes.pointer(device_state)

    error_code = sync_read_state_request(
        port, ams_address_pointer, ads_state_pointer, device_state_pointer
    )

    if error_code:
        raise ADSError(error_code)

    return (ads_state.value, device_state.value)

Read the current ADS - state and the machine - state .


def adsSyncReadDeviceInfoReqEx(port, address):
    # type: (int, AmsAddr) -> Tuple[str, AdsVersion]
    """Read the name and the version number of the ADS-server.

    :param int port: local AMS port as returned by adsPortOpenEx()
    :param pyads.structs.AmsAddr address: local or remote AmsAddr
    :rtype: string, AdsVersion
    :return: device name, version

    """
    sync_read_device_info_request = _adsDLL.AdsSyncReadDeviceInfoReqEx

    # Get pointer to the target AMS address
    ams_address_pointer = ctypes.pointer(address.amsAddrStruct())

    # Create buffer to be filled with device name, get pointer to said buffer
    device_name_buffer = ctypes.create_string_buffer(20)
    device_name_pointer = ctypes.pointer(device_name_buffer)

    # Create ADS Version struct and get pointer.
    ads_version = SAdsVersion()
    ads_version_pointer = ctypes.pointer(ads_version)

    error_code = sync_read_device_info_request(
        port, ams_address_pointer, device_name_pointer, ads_version_pointer
    )

    if error_code:
        raise ADSError(error_code)

    return (device_name_buffer.value.decode(), AdsVersion(ads_version))

Read the name and the version number of the ADS - server .


def adsSyncWriteControlReqEx(
    port, address, ads_state, device_state, data, plc_data_type
):
    # type: (int, AmsAddr, int, int, Any, Type) -> None
    """Change the ADS state and the machine-state of the ADS-server.

    :param int port: local AMS port as returned by adsPortOpenEx()
    :param pyads.structs.AmsAddr adr: local or remote AmsAddr
    :param int ads_state: new ADS-state, according to ADSTATE constants
    :param int device_state: new machine-state
    :param data: additional data
    :param int plc_data_type: plc datatype, according to PLCTYPE constants

    """
    sync_write_control_request = _adsDLL.AdsSyncWriteControlReqEx

    ams_address_pointer = ctypes.pointer(address.amsAddrStruct())
    ads_state_c = ctypes.c_ulong(ads_state)
    device_state_c = ctypes.c_ulong(device_state)

    if plc_data_type == PLCTYPE_STRING:
        data = ctypes.c_char_p(data.encode("utf-8"))
        data_pointer = data
        data_length = len(data_pointer.value) + 1
    else:
        data = plc_data_type(data)
        data_pointer = ctypes.pointer(data)
        data_length = ctypes.sizeof(data)

    error_code = sync_write_control_request(
        port,
        ams_address_pointer,
        ads_state_c,
        device_state_c,
        data_length,
        data_pointer,
    )

    if error_code:
        raise ADSError(error_code)

Change the ADS state and the machine - state of the ADS - server .


def adsSyncWriteReqEx(port, address, index_group, index_offset, value, plc_data_type):
    # type: (int, AmsAddr, int, int, Any, Type) -> None
    """Send data synchronous to an ADS-device.

    :param int port: local AMS port as returned by adsPortOpenEx()
    :param pyads.structs.AmsAddr address: local or remote AmsAddr
    :param int indexGroup: PLC storage area, according to the INDEXGROUP
        constants
    :param int index_offset: PLC storage address
    :param value: value to write to the storage address of the PLC
    :param int plc_data_type: type of the data given to the PLC,
        according to PLCTYPE constants

    """
    sync_write_request = _adsDLL.AdsSyncWriteReqEx

    ams_address_pointer = ctypes.pointer(address.amsAddrStruct())
    index_group_c = ctypes.c_ulong(index_group)
    index_offset_c = ctypes.c_ulong(index_offset)

    if plc_data_type == PLCTYPE_STRING:
        data = ctypes.c_char_p(value.encode("utf-8"))
        data_pointer = data  # type: Union[ctypes.c_char_p, ctypes.pointer]
        data_length = len(data_pointer.value) + 1  # type: ignore

    else:
        if type(plc_data_type).__name__ == "PyCArrayType":
            data = plc_data_type(*value)
        else:
            data = plc_data_type(value)

        data_pointer = ctypes.pointer(data)
        data_length = ctypes.sizeof(data)

    error_code = sync_write_request(
        port,
        ams_address_pointer,
        index_group_c,
        index_offset_c,
        data_length,
        data_pointer,
    )

    if error_code:
        raise ADSError(error_code)

Send data synchronous to an ADS - device .


def adsSyncReadReqEx2(
    port, address, index_group, index_offset, data_type, return_ctypes=False
):
    # type: (int, AmsAddr, int, int, Type, bool) -> Any
    """Read data synchronous from an ADS-device.

    :param int port: local AMS port as returned by adsPortOpenEx()
    :param pyads.structs.AmsAddr address: local or remote AmsAddr
    :param int index_group: PLC storage area, according to the INDEXGROUP
        constants
    :param int index_offset: PLC storage address
    :param Type data_type: type of the data given to the PLC, according to
        PLCTYPE constants
    :param bool return_ctypes: return ctypes instead of python types if True
        (default: False)
    :rtype: data_type
    :return: value: **value**

    """
    sync_read_request = _adsDLL.AdsSyncReadReqEx2

    ams_address_pointer = ctypes.pointer(address.amsAddrStruct())
    index_group_c = ctypes.c_ulong(index_group)
    index_offset_c = ctypes.c_ulong(index_offset)

    if data_type == PLCTYPE_STRING:
        data = (STRING_BUFFER * PLCTYPE_STRING)()
    else:
        data = data_type()

    data_pointer = ctypes.pointer(data)
    data_length = ctypes.c_ulong(ctypes.sizeof(data))

    bytes_read = ctypes.c_ulong()
    bytes_read_pointer = ctypes.pointer(bytes_read)

    error_code = sync_read_request(
        port,
        ams_address_pointer,
        index_group_c,
        index_offset_c,
        data_length,
        data_pointer,
        bytes_read_pointer,
    )

    if error_code:
        raise ADSError(error_code)

    # If we're reading a value of predetermined size (anything but a string),
    # validate that the correct number of bytes were read
    if data_type != PLCTYPE_STRING and bytes_read.value != data_length.value:
        raise RuntimeError(
            "Insufficient data (expected {0} bytes, {1} were read).".format(
                data_length.value, bytes_read.value
            )
        )

    if return_ctypes:
        return data

    if data_type == PLCTYPE_STRING:
        return data.value.decode("utf-8")

    if type(data_type).__name__ == "PyCArrayType":
        return [i for i in data]

    if hasattr(data, "value"):
        return data.value

    return data

Read data synchronous from an ADS - device .


def adsSyncReadByNameEx(port, address, data_name, data_type, return_ctypes=False):
    # type: (int, AmsAddr, str, Type, bool) -> Any
    """Read data synchronous from an ADS-device from data name.

    :param int port: local AMS port as returned by adsPortOpenEx()
    :param pyads.structs.AmsAddr address: local or remote AmsAddr
    :param string data_name: data name
    :param Type data_type: type of the data given to the PLC, according to
        PLCTYPE constants
    :param bool return_ctypes: return ctypes instead of python types if True
        (default: False)
    :rtype: data_type
    :return: value: **value**

    """
    # Get the handle of the PLC-variable
    handle = adsSyncReadWriteReqEx2(
        port,
        address,
        ADSIGRP_SYM_HNDBYNAME,
        0x0,
        PLCTYPE_UDINT,
        data_name,
        PLCTYPE_STRING,
    )

    # Read the value of a PLC-variable, via handle
    value = adsSyncReadReqEx2(
        port, address, ADSIGRP_SYM_VALBYHND, handle, data_type, return_ctypes
    )

    # Release the handle of the PLC-variable
    adsSyncWriteReqEx(port, address, ADSIGRP_SYM_RELEASEHND, 0, handle, PLCTYPE_UDINT)

    return value

Read data synchronous from an ADS - device from data name .


def adsSyncWriteByNameEx(port, address, data_name, value, data_type):
    # type: (int, AmsAddr, str, Any, Type) -> None
    """Send data synchronous to an ADS-device from data name.

    :param int port: local AMS port as returned by adsPortOpenEx()
    :param pyads.structs.AmsAddr address: local or remote AmsAddr
    :param string data_name: PLC storage address
    :param value: value to write to the storage address of the PLC
    :param Type data_type: type of the data given to the PLC,
        according to PLCTYPE constants

    """
    # Get the handle of the PLC-variable
    handle = adsSyncReadWriteReqEx2(
        port,
        address,
        ADSIGRP_SYM_HNDBYNAME,
        0x0,
        PLCTYPE_UDINT,
        data_name,
        PLCTYPE_STRING,
    )

    # Write the value of a PLC-variable, via handle
    adsSyncWriteReqEx(port, address, ADSIGRP_SYM_VALBYHND, handle, value, data_type)

    # Release the handle of the PLC-variable
    adsSyncWriteReqEx(port, address, ADSIGRP_SYM_RELEASEHND, 0, handle, PLCTYPE_UDINT)

Send data synchronous to an ADS - device from data name .