Пример #1
0
    def __init__(
        self,
        context,
        name,
        parent,  # Standard visr component constructor arguments
        numberOfObjects,  # The number of point source objects rendered.
        hoaOrder,  # The Ambisonics order for encoding the objects
        channelAllocation=False  # Whether to allocate object channels dynamically (not used at the moment)
    ):
        """
        Constructor.

        Parameters
        ----------
        numberOfObjects: int
            The maximum number of audio objects to be rendered.
        hoaOrder: int
            The Ambisonics order for encoding the objects.
        channelAllocation: bool, optional
            Whether to send dynamic channel allocation data. Not used at the moment.
            Default value means that the object channels are allocated statically and correspond to the
            obbject's channel id.
        """
        # Call base class (AtomicComponent) constructor
        super(HoaObjectEncoder, self).__init__(context, name, parent)
        self.numberOfObjects = numberOfObjects
        self.hoaOrder = hoaOrder
        self.numHoaCoeffs = (self.hoaOrder + 1)**2

        # %% Define parameter ports
        self.objectInput = visr.ParameterInput(
            "objectVector", self, pml.ObjectVector.staticType,
            pml.DoubleBufferingProtocol.staticType, pml.EmptyParameterConfig())
        self.objectInputProtocol = self.objectInput.protocolInput()

        matrixConfig = pml.MatrixParameterConfig(self.numHoaCoeffs,
                                                 self.numberOfObjects)
        self.coefficientOutput = visr.ParameterOutput(
            "coefficientOutput", self, pml.MatrixParameterFloat.staticType,
            pml.SharedDataProtocol.staticType, matrixConfig)
        self.coefficientOutputProtocol = self.coefficientOutput.protocolOutput(
        )

        if channelAllocation:
            self.channelAllocator = rbbl.ObjectChannelAllocator(
                self.numberOfObjects)
            self.usedChannels = set()  # Initialised with an empty set.
            self.routingOutput = visr.ParameterOutput(
                "routingOutput", self, pml.SignalRoutingParameter.staticType,
                pml.DoubleBufferingProtocol.staticType,
                pml.EmptyParameterConfig())
            self.routingOutputProtocol = self.routingOutput.protocolOutput()
        else:
            self.routingOutputProtocol = None
            self.channelAllocator = None
Пример #2
0
 def __init__( self, context, name, parent,
              processorConfig,
              objectVectorInput = True,  # receive input as pml.ObjectVector parameters (as opposed to JSON)
              objectVectorOutput = True, # send output as pml.ObjectVector parameters (as opposed to JSON)
              oscControlPort = False,
              jsonControlPort = False,
              alwaysProcess = True,
              verbose = False):
     """ Construction function. """
     super( Component, self ).__init__( context, name, parent )
     if objectVectorInput:
         self.textInput = False
         self.objectInput = visr.ParameterInput( "objectIn", self,
                                                pml.ObjectVector.staticType,
                                                pml.DoubleBufferingProtocol.staticType,
                                                pml.EmptyParameterConfig() )
     else:
         self.textInput = True
         self.objectInput = visr.ParameterInput( "objectIn", self,
                                                pml.StringParameter.staticType,
                                                pml.MessageQueueProtocol.staticType,
                                                pml.EmptyParameterConfig() )
     if objectVectorOutput:
         self.textOutput = False
         self.objectOutput = visr.ParameterOutput( "objectOut", self,
                                                pml.ObjectVector.staticType,
                                                pml.DoubleBufferingProtocol.staticType,
                                                pml.EmptyParameterConfig() )
     else:
         self.textOutput = True
         self.objectOutput = visr.ParameterOutput( "objectOut", self,
                                                pml.StringParameter.staticType,
                                                pml.MessageQueueProtocol.staticType,
                                                pml.EmptyParameterConfig() )
     if oscControlPort:
         self.oscControlInput = visr.ParameterInput( "oscControlIn", self,
                                                pml.StringParameter.staticType,
                                                pml.MessageQueueProtocol.staticType,
                                                pml.EmptyParameterConfig() )
     else:
         self.oscControlInput = None
     if jsonControlPort:
         self.jsonControlInput = visr.ParameterInput( "jsonControlIn", self,
                                                pml.StringParameter.staticType,
                                                pml.MessageQueueProtocol.staticType,
                                                pml.EmptyParameterConfig() )
     else:
         self.jsonControlInput = None
     self._engine = Engine( processorConfig, alwaysProcess, verbose )
    def __init__(self, context, name, parent, *, calibrationPort, **razorArgs):
        """
        Constructor.

        context : visr.SignalFlowContext
            Standard visr.Component construction argument, a structure holding the block size and the sampling frequency
        name : string
            Name of the component, Standard visr.Component construction argument
        parent : visr.CompositeComponent
            Containing component if there is one, None if this is a top-level component of the signal flow.
        calibrationPort: int
            A UDP port number. Packets sent to this port trigger the calibration.
        razorArg: keyword list
            Set of parameters to the RazorAHRS. See this class for parameter documentation.
        """
        super(RazorAHRSWithUdpCalibrationTrigger,
              self).__init__(context, name, parent)
        self.trackingOutput = visr.ParameterOutput(
            "orientation", self, pml.ListenerPosition.staticType,
            pml.DoubleBufferingProtocol.staticType, pml.EmptyParameterConfig())

        razorArgs[
            'calibrationInput'] = True  # Reset the keyword argument (if already present)
        self.tracker = RazorAHRS(context, "Tracker", self, **razorArgs)
        self.triggerReceiver = UdpReceiver(context,
                                           "CalibrationTriggerReceiver",
                                           self,
                                           port=calibrationPort)
        self.parameterConnection(
            self.triggerReceiver.parameterPort("messageOutput"),
            self.tracker.parameterPort("calibration"))
        self.parameterConnection(self.tracker.parameterPort("orientation"),
                                 self.trackingOutput)
Пример #4
0
    def __init__(self,
                 context,
                 name,
                 parent,
                 numberOfChannels,
                 measurePeriod=0.4,
                 channelWeights=None,
                 audioOut=False):
        # Call the base class constructor
        super(LoudnessMeter, self).__init__(context, name, parent)
        # Define an audio input port with name "audioIn" and width (number of signal waveforms) numberOfChannels
        self.audioInput = visr.AudioInputFloat("audioIn", self,
                                               numberOfChannels)

        # If the option is set, add an audio output to put out the K-weigth input signals
        # Some audio interfaces don't like configs with no outputs.
        if audioOut:
            self.audioOutput = visr.AudioOutputFloat("audioOut", self,
                                                     numberOfChannels)
        else:
            self.audioOutput = None

        # Define a parameter output port with type "Float" and communication protocol "MessageQueue"
        # MessageQueue means that all computed data are hold in a first-in-first-out queue,
        # which decouples the parameter update rate from the buffer size.
        self.loudnessOut = visr.ParameterOutput(
            "loudnessOut", self, pml.Float.staticType,
            pml.MessageQueueProtocol.staticType, pml.EmptyParameterConfig())

        # %% Setup data used in the process() function.

        # Round the measurement period to the next multiple of the buffer period
        numMeanBlocks = int(
            np.ceil(
                (measurePeriod * context.samplingFrequency) / context.period))
        self.pastPower = np.zeros(numMeanBlocks, dtype=np.float32)

        # IIR filter state to be saved in betweem
        self.filterState = np.zeros((2, numberOfChannels, 2), dtype=np.float32)

        # IIR coefficients for K-weighting, taken from ITU-R BS.1770-4
        # https://www.itu.int/dms_pubrec/itu-r/rec/bs/R-REC-BS.1770-4-201510-I!!PDF-E.pdf
        self.Kweighting = np.asarray([[
            1.53512485958697, -2.69169618940638, 1.19839281085285, 1.0,
            -1.69065929318241, 0.73248077421585
        ], [1.0, -2.0, 1.0, 1.0, -1.99004745483398, 0.99007225036621]],
                                     dtype=np.float32)

        # Initialise weightings for the channels.
        # Use unit weighting if none are given
        if channelWeights is not None:
            self.channelWeights = np.asarray(channelWeights, dtype=np.float32)
            if self.channelWeights.shape[0] != numberOfChannels:
                raise ValueError(
                    "The channelWeights argument does not match the number of channels"
                )
        else:
            self.channelWeights = np.ones(numberOfChannels, dtype=np.float32)
Пример #5
0
    def __init__( self,
                  context, name, parent,
                  numberOfObjects,
                  hoaOrder,
                  dynamicUpdates = False,
                  headOrientation = None
                  ):
        """
        Constructor.

        Parameters
        ----------
        context: visr.SignalFlowContext
            Structure containing block size and sampling frequency, standard visr component construction parameter.
        name: string
            Name of the component, can be chosen freely as long as it is unique withion the containing component.
        parent: visr.CompositeComponent or NoneType
            The containing composite component, or None for a top-level component.
        numberOfObjects: int
            The number of objects to be rendered, i.e., columns in the received spherical harmonics matrices.
        hoaOrder: int
            The order of the spherical harmonics. Defines the number of rows of the processed matrices ((hoaOrder+1)^2)
        headOrientation: array-like (2- or 3- element) or NoneType
            The initial head rotation or the static head orientation if dynamic updates are deactivated. Given as yaw, pitch, roll.
        """
        # Call base class (AtomicComponent) constructor
        super( HoaCoefficientRotation, self ).__init__( context, name, parent )
        self.numberOfObjects = numberOfObjects
        self.hoaOrder = hoaOrder
        self.numHoaCoeffs = (self.hoaOrder+1)**2

        # %% Define parameter ports
        matrixConfig = pml.MatrixParameterConfig( self.numHoaCoeffs, self.numberOfObjects )
        self.coefficientInput = visr.ParameterInput( "coefficientInput", self,
                                                pml.MatrixParameterFloat.staticType,
                                                pml.SharedDataProtocol.staticType,
                                                matrixConfig )
        self.coefficientInputProtocol = self.coefficientInput.protocolInput()
        self.coefficientOutput = visr.ParameterOutput( "coefficientOutput", self,
                                                pml.MatrixParameterFloat.staticType,
                                                pml.SharedDataProtocol.staticType,
                                                matrixConfig )
        self.coefficientOutputProtocol = self.coefficientOutput.protocolOutput()

        # Instantiate the head tracker input.
        self.trackingInput = visr.ParameterInput( "tracking", self, pml.ListenerPosition.staticType,
                                                  pml.DoubleBufferingProtocol.staticType,
                                                  pml.EmptyParameterConfig() )
        self.trackingInputProtocol = self.trackingInput.protocolInput()

        if headOrientation is None:
            headOrientation = np.zeros( (3), np.float32 )
        R1 = rotationMatrixReorderingACN( calcRotationMatrix( headOrientation ) )
        self.rotationMatrices = allSphericalHarmonicsRotationMatrices( self.hoaOrder, R1 )
    def __init__(
            self,
            context,
            name,
            parent,
            positions,  # Either #points x 3 or 1x3 matrix of Cartesian object positions.
            updateRateSamples=None,
            objectId=0,
            groupId=0,
            priority=0,
            objectLevel=1.0,
            objectChannel=None,
            diffuseness=None):
        super(PointSourceTrajectoryGenerator,
              self).__init__(context, name, parent)
        if updateRateSamples % self.period() != 0:
            raise ValueError(
                "TrajectoryGenerator: The update rate must be a multiple of the period."
            )
        self.updateCycles = updateRateSamples // self.period()

        self.positions = positions
        self.numPositions = self.positions.shape[1]

        self.objectOutput = visr.ParameterOutput(
            "objectVectorOutput",
            self,
            parameterType=pml.ObjectVector.staticType,
            protocolType=pml.DoubleBufferingProtocol.staticType,
            parameterConfig=pml.EmptyParameterConfig())
        self.cycleCounter = 0
        self.positionCounter = 0

        if diffuseness is None:
            self.object = om.PointSource(objectId)
        else:
            ValueError("Diffuse point sources not currently supported.")

        self.object.position = positions[:, 0]
        self.object.level = objectLevel
        self.groupId = groupId
        self.object.priority = priority
        if objectChannel is None:
            objectChannel = objectId
        self.object.channels = [objectChannel]
Пример #7
0
 def __init__(
     self,
     context,
     name,
     parent,
     arrayConfig,
     numberOfObjects=1,
 ):
     super(PythonPanner, self).__init__(context, name, parent)
     self.numLsp = arrayConfig.numberOfRegularLoudspeakers
     self.objectInput = visr.ParameterInput(
         "objectVectorInput",
         self,
         parameterType=pml.ObjectVector.staticType,
         protocolType=pml.DoubleBufferingProtocol.staticType,
         parameterConfig=pml.EmptyParameterConfig())
     self.gainOutput = visr.ParameterOutput(
         "gainOutput",
         self,
         parameterType=pml.MatrixParameterFloat.staticType,
         protocolType=pml.SharedDataProtocol.staticType,
         parameterConfig=pml.MatrixParameterConfig(self.numLsp,
                                                   numberOfObjects))
     self.vbap = panning.VBAP(arrayConfig)
Пример #8
0
    def __init__( self,
                  context, name, parent,
                  port,
                  yawOffset=0,
                  pitchOffset=0,
                  rollOffset=0,
                  yawRightHand=False,
                  pitchRightHand=False,
                  rollRightHand=False,
                  calibrationInput = False # Whether to instantiate an input port to set the orientation.
                  ):
        """
        Constructor.


        Parameters
        ----------
        context : visr.SignalFlowContext
            Standard visr.Component construction argument, a structure holding the block size and the sampling frequency
        name : string
            Name of the component, Standard visr.Component construction argument
        parent : visr.CompositeComponent
            Containing component if there is one, None if this is a top-level component of the signal flow.
        yawOffset:
            Initial offset for the yaw component, default 0.0
        pitchOffset :  float
            Offset for the pitch value, in degree
        rollOffset : float:
            Initial value for the roll component, default 0.0
        yawRightHand: bool
            Whehther the yaw coordinate is interpreted as right-hand
            (mathematically negative) rotation. Default: False
        pitchRightHand: bool
            Whehther the pitch coordinate is interpreted as right-hand
            (mathematically negative) rotation. Default: False
        rollRightHand: bool
            Whehther the roll coordinate is interpreted as right-hand
            (mathematically negative) rotation. Default: False
        calibrationInput: bool
            Flag to determine whehter the component has an additional input "calibration"
            that resets the orientation offsets. At the moment, this input is of
            type StringParameter, and the value is ignored.

        TODO: Check whether to support ListenerPosition objects as calibration triggers
        to set the orientation to an arbitrary value
        """


        super( RazorAHRS, self ).__init__( context, name, parent )
        self.yprVec =   np.zeros( 3, dtype = np.float32 )
        baudRate = 57600
        self.ser = serial.Serial(port, baudRate, timeout=0)
        self.message = ""
        self.sent = False
        self.trackingOutput = visr.ParameterOutput( "orientation", self,
                                              pml.ListenerPosition.staticType,
                                              pml.DoubleBufferingProtocol.staticType,
                                              pml.EmptyParameterConfig() )
        self.trackingOutputProtocol = self.trackingOutput.protocolOutput()

        if calibrationInput:
            self.calibrationInput = visr.ParameterInput( "calibration", self,
                                                         pml.StringParameter.staticType,
                                                         pml.MessageQueueProtocol.staticType,
                                                         pml.EmptyParameterConfig() )
        else:
            self.calibrationInput = None

        self.sentN = 0
        self.parsedN = 0
        self.ser.read() #necessary for the .in_waiting to work
        self.procN =0
        self.yawOffset = yawOffset
        self.pitchOffset = pitchOffset
        self.rollOffset = rollOffset
        self.yawRightHand = yawRightHand
        self.pitchRightHand = pitchRightHand
        self.rollRightHand= rollRightHand
        self.orientation = np.array( [0.0, 0.0, 0.0 ] ) # Current orientation, unadjusted, in radian
    def __init__( self,
                  context, name, parent,    # Standard visr component constructor arguments
                  numberOfObjects,          # The number of point source objects rendered.
                  hrirPositions,            # The directions of the HRTF measurements, given as a Nx3 array
                  hrirData,                 # The HRTF data as 3 Nx2xL matrix, with L as the FIR length.
                  headRadius = 0.0875,      # Head radius, optional. Might be used in a dynamic ITD/ILD individualisation algorithm.
                  useHeadTracking = False,        # Whether head tracking data is provided via a self.headOrientation port.
                  dynamicITD = False,             # Whether ITD delays are calculated and sent via a "delays" port.
                  dynamicILD = False,             # Whether ILD gains are calculated and sent via a "gains" port.
                  interpolatingConvolver = False, # Whether to transmit interpolation parameters (True) or complete interpolated filters
                  hrirInterpolation = False, # HRTF interpolation selection: False: Nearest neighbour, True: Barycentric (3-point) interpolation
                  channelAllocation = False, # Whether to allocate object channels dynamically (not tested yet)
                  hrirDelays = None,         # Matrix of delays associated with filter dataset. Dimension: # filters * 2
                  ):
        """
        Constructor.

        Parameters
        ----------
        context : visr.SignalFlowContext
            Standard visr.Component construction argument, a structure holding the block size and the sampling frequency
        name : string
            Name of the component, Standard visr.Component construction argument
        parent : visr.CompositeComponent
            Containing component if there is one, None if this is a top-level component of the signal flow.
        numberOfObjects: int
            The number of point source objects rendered.
        hrirPositions : numpy.ndaarray
            The directions of the HRTF measurements, given as a Nx3 array
        hrirData : numpy.ndarray
            The HRTF data as 3 Nx2xL matrix, with L as the FIR length.
        headRadius: float
            Head radius, optional and not currently used. Might be used in a dynamic ITD/ILD individualisation algorithm.
        useHeadTracking: bool
            Whether head tracking data is provided via a self.headOrientation port.
        dynamicITD: bool
            Whether ITD delays are calculated and sent via a "delays" port.
        dynamicILD: bool
            Whether ILD gains are calculated and sent via a "gains" port.
        hrirInterpolation: bool
            HRTF interpolation selection: False: Nearest neighbour, True: Barycentric (3-point) interpolation
        channelAllocation: bool
            Whether to allocate object channels dynamically (not tested yet)
        hrirDelays: numpy.ndarray
            Matrix of delays associated with filter dataset. Dimension: # filters * 2. Default None means there are no separate
            delays, i.e., they must be contained in the HRIR data.
        """
        # Call base class (AtomicComponent) constructor
        super( DynamicHrirController, self ).__init__( context, name, parent )
        self.numberOfObjects = numberOfObjects
        self.dynamicITD = dynamicITD
        self.dynamicILD = dynamicILD
        # %% Define parameter ports
        self.objectInput = visr.ParameterInput( "objectVector", self, pml.ObjectVector.staticType,
                                              pml.DoubleBufferingProtocol.staticType,
                                              pml.EmptyParameterConfig() )
        self.objectInputProtocol = self.objectInput.protocolInput()

        if useHeadTracking:
            self.useHeadTracking = True
            self.trackingInput = visr.ParameterInput( "headTracking", self, pml.ListenerPosition.staticType,
                                              pml.DoubleBufferingProtocol.staticType,
                                              pml.EmptyParameterConfig() )
            self.trackingInputProtocol = self.trackingInput.protocolInput()

        else:
            self.useHeadTracking = False
            self.trackingInputProtocol = None # Flag that head tracking is not used.
        self.rotationMatrix = np.identity( 3, dtype=np.float32 )

        self.interpolatingConvolver = interpolatingConvolver
        if interpolatingConvolver:
            self.filterOutputProtocol = None # Used as flag to distinguish between the output modes.

            if not hrirInterpolation:
                numInterpolants = 1
            elif hrirPositions.shape[-1] == 2:
                numInterpolants = 2
            else:
                numInterpolants = 3

            self.interpolationOutput = visr.ParameterOutput( "interpolatorOutput", self,
                                                     pml.InterpolationParameter.staticType,
                                                     pml.MessageQueueProtocol.staticType,
                                                     pml.InterpolationParameterConfig(numInterpolants) )
            self.interpolationOutputProtocol = self.interpolationOutput.protocolOutput()
        else:
            self.filterOutput = visr.ParameterOutput( "filterOutput", self,
                                                     pml.IndexedVectorFloat.staticType,
                                                     pml.MessageQueueProtocol.staticType,
                                                     pml.EmptyParameterConfig() )
            self.filterOutputProtocol = self.filterOutput.protocolOutput()
            self.interpolationOutputProtocol = None

        if self.dynamicITD:
            if (hrirDelays is None) or (hrirDelays.ndim != 2) or (hrirDelays.shape != (hrirData.shape[0], 2 ) ):
                raise ValueError( 'If the "dynamicITD" option is given, the parameter "delays" must be a #hrirs x 2 matrix.' )
            self.dynamicDelays = np.array(hrirDelays, copy=True)
            self.delayOutput = visr.ParameterOutput( "delayOutput", self,
                                                    pml.VectorParameterFloat.staticType,
                                                    pml.DoubleBufferingProtocol.staticType,
                                                    pml.VectorParameterConfig( 2*self.numberOfObjects) )
            self.delayOutputProtocol = self.delayOutput.protocolOutput()

        # If we use dynamic ILD, only the object level is set at the moment.
        if self.dynamicILD:
            self.gainOutput = visr.ParameterOutput( "gainOutput", self,
                                                   pml.VectorParameterFloat.staticType,
                                                   pml.DoubleBufferingProtocol.staticType,
                                                   pml.VectorParameterConfig( 2*self.numberOfObjects) )
            self.gainOutputProtocol = self.gainOutput.protocolOutput()

        if channelAllocation:
            self.routingOutput = visr.ParameterOutput( "routingOutput", self,
                                                     pml.SignalRoutingParameter.staticType,
                                                     pml.DoubleBufferingProtocol.staticType,
                                                     pml.EmptyParameterConfig() )
            self.routingOutputProtocol = self.routingOutput.protocolOutput()
        else:
            self.routingOutputProtocol = None

        # HRIR selection and interpolation data
        # If the interpolatingconvolver is used, only interpolation parameters are transmitted.
        if interpolatingConvolver:
            self.hrirs = None
        else:
            self.hrirs = np.array( hrirData, copy = True, dtype = np.float32 )

        # Normalise the hrir positions to unit radius (to let the k-d tree
        # lookup work as expected.)
        hrirPositions[:,2] = 1.0
        self.hrirPos = sph2cart(np.array( hrirPositions, copy = True, dtype = np.float32 ))
        self.hrirInterpolation = hrirInterpolation
        if self.hrirInterpolation:
            self.lastPosition = np.repeat( [[np.NaN, np.NaN, np.NaN]], self.numberOfObjects, axis=0 )
            self.hrirLookup = ConvexHull( self.hrirPos )
            self.triplets = np.transpose(self.hrirLookup.points[self.hrirLookup.simplices], axes=(0, 2, 1))
            self.inverted = np.asarray( inv(self.triplets), dtype=np.float32 )
        else:
            self.lastFilters = np.repeat( -1, self.numberOfObjects, axis=0 )

        # %% Dynamic allocation of objects to channels
        if channelAllocation:
            self.channelAllocator = rbbl.ObjectChannelAllocator( self.numberOfObjects )
            self.usedChannels = set()
        else:
            self.channelAllocator = None
            self.sourcePos = np.repeat( np.array([[1.0,0.0,0.0]],
                                        dtype = np.float32 ), self.numberOfObjects, axis = 0 )
            self.levels = np.zeros( (self.numberOfObjects), dtype = np.float32 )
Пример #10
0
    def __init__(self,
                 context,
                 name,
                 parent,
                 hoaOrder,
                 dynamicOrientation=False,
                 initialOrientation=None):
        """
        Constructor.

        Parameters
        ----------
        context: visr.SignalFlowContext
            Structure containing block size and sampling frequency, standard visr component construction parameter.
        name: string
            Name of the component, can be chosen freely as long as it is unique withion the containing component.
        parent: visr.CompositeComponent or NoneType
            The containing composite component, or None for a top-level component.
        hoaOrder: int
            The spherical harmonics order, determines the size of the output matrix.
        dynamicOrientation: bool
            Whether the orientation is updated at runtime. If True, a parmater input
            "orientation" is instantiated that receivers pml.ListenerPositions
        initialOrientation: array-like (2- or 3- element) or NoneType
            The initial head rotation or the static head orientation if dynamic updates are deactivated. Given as yaw, pitch, roll.
        """
        # Call base class (AtomicComponent) constructor
        super(HoaRotationMatrixCalculator,
              self).__init__(context, name, parent)
        self.hoaOrder = hoaOrder
        self.numHoaCoeffs = (self.hoaOrder + 1)**2

        # Number of nonzero matrix coefficients.
        # Explisit formula sum( (2i+1)^2 ) for i = 0 .. hoaOrder
        # This is always an integer (i.e., multiple of 3 before division).
        self.numMatrixCoeffs = ((hoaOrder + 1) * (2 * hoaOrder + 1) *
                                (2 * hoaOrder + 3)) // 3

        # %% Define parameter ports
        outConfig = pml.VectorParameterConfig(self.numMatrixCoeffs)
        self.coeffOutput = visr.ParameterOutput(
            "coefficients", self, pml.VectorParameterFloat.staticType,
            pml.DoubleBufferingProtocol.staticType, outConfig)
        self.coeffOutputProtocol = self.coeffOutput.protocolOutput()

        if dynamicOrientation:
            self.orientationInput = visr.ParameterInput(
                "orientation", self, pml.ListenerPosition.staticType,
                pml.DoubleBufferingProtocol.staticType,
                pml.EmptyParameterConfig())
            self.orientationInputProtocol = self.orientationInput.protocolInput(
            )
        else:
            self.orientationInputProtocol is None

        if initialOrientation is None:
            initialOrientation = np.zeros((3), np.float32)
        else:
            initialOrientation = np.asarray(initialOrientation,
                                            dtype=np.float32)
            if initialOrientation.size < 3:
                initialOrientation = np.concatenate(
                    (initialOrientation,
                     np.zeros(3 - initialOrientation.size, dtype=np.float32)))
        R1 = rotationMatrixReorderingACN(
            calcRotationMatrix(initialOrientation))
        self.rotationMatrices = allSphericalHarmonicsRotationMatrices(
            self.hoaOrder, R1)