void Ambix_converterAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) { // do the audio processing.... // defines are until 10th order 3d (121 channels)! // resize output buffer if necessare int NumSamples = buffer.getNumSamples(); output_buffer.setSize(std::max(getNumOutputChannels(), getNumInputChannels()), NumSamples); output_buffer.clear(); // in case of 2d where we might throw away some channels // std::cout << "NumInputChannels: " << getNumInputChannels() << " Buffersize: " << buffer.getNumChannels() << std::endl; for (int i = 0; i < getNumInputChannels(); i++) // iterate over acn channel numbering { int l = 0; // sometimes called n int m = 0; // -l...l ACNtoLM(i, l, m); int _in_ch_seq = in_ch_seq[i]; int _out_ch_seq = out_ch_seq[i]; if (in_2d) { _in_ch_seq = in_2d_ch_seq[ACN3DtoACN2D(i)]; if (_in_ch_seq > getNumInputChannels()) _in_ch_seq = -1; } if (out_2d) { _out_ch_seq = out_2d_ch_seq[ACN3DtoACN2D(i)]; if (_out_ch_seq > getNumOutputChannels()) _out_ch_seq = -1; } // std::cout << "InputCh: " << i << " IN_CHANNEL: " << _in_ch_seq << " OUT_CHANNEL: " << _out_ch_seq << std::endl; if (_in_ch_seq != -1 && _out_ch_seq != -1 && _in_ch_seq < getNumInputChannels()) { // copy input channels to output channels! output_buffer.copyFrom(_out_ch_seq, 0, buffer, _in_ch_seq, 0, NumSamples); // apply normalization conversion gain if different input/output scheme if (!ch_norm_flat) { output_buffer.applyGain(_out_ch_seq, 0, NumSamples, in_ch_norm[i]); } // do the inversions... if (flip_cs_phase || flip_param || flop_param || flap_param) { signed int flip, flop, flap, total; flip = flop = flap = total = 1; // taken from paper Symmetries of Spherical Harmonics by Michael Chapman (Ambi Symp 2009), // mirror left right if ( flip_param && (m < 0) ) // m < 0 -> invert flip = -1; // mirror front back if ( flop_param && ( ((m < 0) && !(m % 2)) || ((m >= 0) && (m % 2)) ) ) // m < 0 and even || m >= 0 and odd flop = -1; // mirror top bottom if ( flap_param && ( (l + m) % 2 ) ) // l+m odd ( (odd, even) or (even, odd) ) flap = -1; // compute total multiplicator if (flip_cs_phase) total = acn_cs[i] * flip * flop * flap; else total = flip * flop * flap; output_buffer.applyGain(_out_ch_seq, 0, NumSamples, (float)total); } } // index not -1 } // iterate over all input channels // In case we have more outputs than inputs, we'll clear any output // channels that didn't contain input data, (because these aren't // guaranteed to be empty - they may contain garbage). /* for (int i = getNumInputChannels(); i < getNumOutputChannels(); ++i) { output_buffer.clear (i, 0, buffer.getNumSamples()); } */ buffer = output_buffer; }
void Ambix_wideningAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) { // backup old coefficients memcpy(_cos_coeffs, cos_coeffs, sizeof(float)*AMBI_ORDER*(BESSEL_APPR+1)); memcpy(_sin_coeffs, sin_coeffs, sizeof(float)*AMBI_ORDER*(BESSEL_APPR+1)); // calc new coefficients calcParams(); ////////////////////// // write to the buffer if (_buf_write_pos + buffer.getNumSamples() < _buf_size) { for (int ch = 0; ch < buffer.getNumChannels(); ch++) { // copy straight into buffer ring_buffer.copyFrom(ch, _buf_write_pos, buffer, ch, 0, buffer.getNumSamples()); } // update write position _buf_write_pos += buffer.getNumSamples(); } else { // if buffer reaches end int samples_to_write1 = _buf_size - _buf_write_pos; int samples_to_write2 = buffer.getNumSamples() - samples_to_write1; // std::cout << "spl_write1: " << samples_to_write1 << " spl_write2: " << samples_to_write2 << std::endl; for (int ch = 0; ch < buffer.getNumChannels(); ch++) { // copy until end ring_buffer.copyFrom(ch, _buf_write_pos, buffer, ch, 0, samples_to_write1); // start copy to front ring_buffer.copyFrom(ch, 0, buffer, ch, samples_to_write1, samples_to_write2); } // update write position _buf_write_pos = samples_to_write2; } // String debug = String::empty; ///////////////////////// // compute read positions (tap delay times) // Q is computed in calcParams() (SampleRate dependent) for (int i=0; i < BESSEL_APPR*2+1; i++) { _buf_read_pos[i] = _buf_write_pos - i*Q - buffer.getNumSamples(); if (_buf_read_pos[i] < 0) _buf_read_pos[i] = _buf_size + _buf_read_pos[i]; // -1 ? // debug << _buf_read_pos[i] << " "; } // std::cout << "read pos: " << debug << std::endl; ///////////////////////// // do the rotation buffer.clear(); int fir_length = 2*BESSEL_APPR+1; if (single_sided) fir_length = BESSEL_APPR+1; for (int acn_out = 0; acn_out < getTotalNumOutputChannels(); acn_out++) // iterate over output channels { int l_out = 0; int m_out = 0; ACNtoLM(acn_out, l_out, m_out); for (int acn_in = 0; acn_in < getTotalNumInputChannels(); acn_in++) // iterate over input channels { int l_in=0; // degree 0, 1, 2, 3, 4, ... int m_in=0; // order ..., -2, -1, 0 , 1, 2, ... ACNtoLM(acn_in, l_in, m_in); if (abs(m_out) == abs (m_in) && l_in == l_out) { // if degree and order match do something int pos_index = 0; // index of _buf_read_pos /////////////// // pass through terms (z symmetric, m=0) if (m_out == 0 && m_in == 0) { if (!single_sided) pos_index = BESSEL_APPR; // read from buffer if (_buf_read_pos[pos_index] + buffer.getNumSamples() < _buf_size) { buffer.copyFrom(acn_out, 0, ring_buffer, acn_out, _buf_read_pos[pos_index], buffer.getNumSamples()); } else { int samples_to_read1 = _buf_size - _buf_read_pos[pos_index]; int samples_to_read2 = buffer.getNumSamples() - samples_to_read1; // copy until end buffer.copyFrom(acn_out, 0, ring_buffer, acn_out, _buf_read_pos[pos_index], samples_to_read1); // start copy from front buffer.copyFrom(acn_out, samples_to_read1, ring_buffer, acn_out, 0, samples_to_read2); } } /////////////// // cosine terms else if (m_in < 0 && m_out < 0) // cosine { for (int i=0; i < fir_length; i++) { // ITERATE BESSEL APPR int j = abs(i-BESSEL_APPR); if (single_sided) j=i; float _coeff = _cos_coeffs[l_in-1][j]; float coeff = cos_coeffs[l_in-1][j]; if (coeff != 0.f) { // skip zero coefficients // read from buffer if (_buf_read_pos[i] + buffer.getNumSamples() < _buf_size) { if (_coeff != coeff) // interpolate? buffer.addFromWithRamp(acn_out, 0, ring_buffer.getReadPointer(acn_in, _buf_read_pos[i]), buffer.getNumSamples(), _coeff, coeff); else buffer.addFrom(acn_out, 0, ring_buffer, acn_in, _buf_read_pos[i], buffer.getNumSamples(), coeff); } else { int samples_to_read1 = _buf_size - _buf_read_pos[i]; int samples_to_read2 = buffer.getNumSamples() - samples_to_read1; // copy until end if (_coeff != coeff) // interpolate? buffer.addFromWithRamp(acn_out, 0, ring_buffer.getReadPointer(acn_in, _buf_read_pos[i]), samples_to_read1, _coeff, coeff); else buffer.addFrom(acn_out, 0, ring_buffer, acn_in, _buf_read_pos[i], samples_to_read1, coeff); // start copy from front if (_coeff != coeff) // interpolate? buffer.addFromWithRamp(acn_out, samples_to_read1, ring_buffer.getReadPointer(acn_in, 0), samples_to_read2, _coeff, coeff); else buffer.addFrom(acn_out, samples_to_read1, ring_buffer, acn_in, 0, samples_to_read2, coeff); } } } // end iterate BESSEL_APPR } /////////////// // -sine terms else if (m_in < 0 && m_out > 0) // -sine { for (int i=0; i < fir_length; i++) { // ITERATE BESSEL APPR int j = abs(i-BESSEL_APPR); if (single_sided) j=i; float _coeff = -_sin_coeffs[l_in-1][j]; float coeff = -sin_coeffs[l_in-1][j]; if (coeff != 0.f) { // skip zero coefficients // read from buffer if (_buf_read_pos[i] + buffer.getNumSamples() < _buf_size) { if (_coeff != coeff) // interpolate? buffer.addFromWithRamp(acn_out, 0, ring_buffer.getReadPointer(acn_in, _buf_read_pos[i]), buffer.getNumSamples(), _coeff, coeff); else buffer.addFrom(acn_out, 0, ring_buffer, acn_in, _buf_read_pos[i], buffer.getNumSamples(), coeff); } else { int samples_to_read1 = _buf_size - _buf_read_pos[i]; int samples_to_read2 = buffer.getNumSamples() - samples_to_read1; // copy until end if (_coeff != coeff) // interpolate? buffer.addFromWithRamp(acn_out, 0, ring_buffer.getReadPointer(acn_in, _buf_read_pos[i]), samples_to_read1, _coeff, coeff); else buffer.addFrom(acn_out, 0, ring_buffer, acn_in, _buf_read_pos[i], samples_to_read1, coeff); // start copy from front if (_coeff != coeff) // interpolate? buffer.addFromWithRamp(acn_out, samples_to_read1, ring_buffer.getReadPointer(acn_in, 0), samples_to_read2, _coeff, coeff); else buffer.addFrom(acn_out, samples_to_read1, ring_buffer, acn_in, 0, samples_to_read2, coeff); } } } // end iterate BESSEL_APPR } /////////////// // cosine terms else if (m_in > 0 && m_out > 0) // cosine { for (int i=0; i < fir_length; i++) { // ITERATE BESSEL APPR int j = abs(i-BESSEL_APPR); if (single_sided) j=i; float _coeff = _cos_coeffs[l_in-1][j]; float coeff = cos_coeffs[l_in-1][j]; if (coeff != 0.f) { // skip zero coefficients // read from buffer if (_buf_read_pos[i] + buffer.getNumSamples() < _buf_size) { if (_coeff != coeff) // interpolate? buffer.addFromWithRamp(acn_out, 0, ring_buffer.getReadPointer(acn_in, _buf_read_pos[i]), buffer.getNumSamples(), _coeff, coeff); else buffer.addFrom(acn_out, 0, ring_buffer, acn_in, _buf_read_pos[i], buffer.getNumSamples(), coeff); } else { int samples_to_read1 = _buf_size - _buf_read_pos[i]; int samples_to_read2 = buffer.getNumSamples() - samples_to_read1; // copy until end if (_coeff != coeff) // interpolate? buffer.addFromWithRamp(acn_out, 0, ring_buffer.getReadPointer(acn_in, _buf_read_pos[i]), samples_to_read1, _coeff, coeff); else buffer.addFrom(acn_out, 0, ring_buffer, acn_in, _buf_read_pos[i], samples_to_read1, coeff); // start copy from front if (_coeff != coeff) // interpolate? buffer.addFromWithRamp(acn_out, samples_to_read1, ring_buffer.getReadPointer(acn_in, 0), samples_to_read2, _coeff, coeff); else buffer.addFrom(acn_out, samples_to_read1, ring_buffer, acn_in, 0, samples_to_read2, coeff); } } } // end iterate BESSEL_APPR } /////////////// // sine terms else if (m_in > 0 && m_out < 0) // sine { for (int i=0; i < fir_length; i++) { // ITERATE BESSEL APPR int j = abs(i-BESSEL_APPR); if (single_sided) j=i; float _coeff = _sin_coeffs[l_in-1][j]; float coeff = sin_coeffs[l_in-1][j]; if (coeff != 0.f) { // skip zero coefficients // read from buffer if (_buf_read_pos[i] + buffer.getNumSamples() < _buf_size) { if (_coeff != coeff) // interpolate? buffer.addFromWithRamp(acn_out, 0, ring_buffer.getReadPointer(acn_in, _buf_read_pos[i]), buffer.getNumSamples(), _coeff, coeff); else buffer.addFrom(acn_out, 0, ring_buffer, acn_in, _buf_read_pos[i], buffer.getNumSamples(), coeff); } else { int samples_to_read1 = _buf_size - _buf_read_pos[i]; int samples_to_read2 = buffer.getNumSamples() - samples_to_read1; // copy until end if (_coeff != coeff) // interpolate? buffer.addFromWithRamp(acn_out, 0, ring_buffer.getReadPointer(acn_in, _buf_read_pos[i]), samples_to_read1, _coeff, coeff); else buffer.addFrom(acn_out, 0, ring_buffer, acn_in, _buf_read_pos[i], samples_to_read1, coeff); // start copy from front if (_coeff != coeff) // interpolate? buffer.addFromWithRamp(acn_out, samples_to_read1, ring_buffer.getReadPointer(acn_in, 0), samples_to_read2, _coeff, coeff); else buffer.addFrom(acn_out, samples_to_read1, ring_buffer, acn_in, 0, samples_to_read2, coeff); } } } // end iterate BESSEL_APPR } } } } }
void Ambix_mirrorAudioProcessor::calcParams() { for (int i=0; i < gain_factors.size(); i++) { gain_factors.set(i, 1.f); } for (int acn = 0; acn < AMBI_CHANNELS; acn++) { float* g = &gain_factors.getReference(acn); int l = 0; // manchmal auch n int m = 0; ACNtoLM(acn, l, m); /////////////// // Z SYMMETRY // z even symmetry if (acn == 0) { *g *= ParamToRMS(z_even_param); if (z_even_inv_param >= 0.5) *g *= -1; } // (l odd, m odd) || (l even, m even) // same as (l+m) even else if ( !((l + m) % 2) ) //else if ( ((l % 2) && (m % 2)) || (!(l % 2) && !(m % 2)) ) { *g *= ParamToRMS(z_even_param); if (z_even_inv_param >= 0.5) *g *= -1; } // z odd symmetry if (acn == 0) { // do nothing } // (l odd, m even) || (l even, m odd) // same as (l+m) odd else if ( ((l + m) % 2) ) //else if ( ((l % 2) && !(m % 2)) || (!(l % 2) && (m % 2))) { *g *= ParamToRMS(z_odd_param); if (z_odd_inv_param >= 0.5) *g *= -1; } ///////////////// // Y SYMMETRY // y even symmetry if (m >= 0) { *g *= ParamToRMS(y_even_param); if (y_even_inv_param >= 0.5) *g *= -1; } // y odd symmetry if (m < 0) { *g *= ParamToRMS(y_odd_param); if (y_odd_inv_param >= 0.5) *g *= -1; } ///////////////// // X SYMMETRY // x even symmetry // m < 0 and odd || m >= 0 and even if ( ((m < 0) && (m % 2)) || ((m >= 0) && !(m % 2)) ) { *g *= ParamToRMS(x_even_param); if (x_even_inv_param >= 0.5) *g *= -1; } // x odd symmetry // m < 0 and even || m >= 0 and odd if ( ((m < 0) && !(m % 2)) || ((m >= 0) && (m % 2)) ) { *g *= ParamToRMS(x_odd_param); if (x_odd_inv_param >= 0.5) *g *= -1; } ///////////////// // BOOST 2D (RING) if (l == m || l == -m) { *g *= ParamToRMS(circular_param); if (circular_inv_param >= 0.5) *g *= -1; } } }
void Ambix_rotator_zAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) { int NumSamples = buffer.getNumSamples(); // resize buffer if necessary output_buffer.setSize((std::max)(getNumOutputChannels(), getNumInputChannels()), NumSamples); // clear output buffer output_buffer.clear(); // save old parameters for interpolation (start ramp) _cos_z = cos_z; _sin_z = sin_z; // calculate new parameters (end ramp) calcParams(); // iterate over input and output channels for z axis rotation // this should work for arbitary ambisonics orders! for (int acn_out = 0; acn_out < getNumOutputChannels(); acn_out++) { int l_out = 0; int m_out = 0; ACNtoLM(acn_out, l_out, m_out); for (int acn_in = 0; acn_in < getNumInputChannels(); acn_in++) { int l_in=0; // degree 0, 1, 2, 3, 4, ...... int m_in=0; // order ...., -2, -1, 0 , 1, 2, ... ACNtoLM(acn_in, l_in, m_in); if (abs(m_out) == abs (m_in) && l_in == l_out) { // if degree and order match do something if (m_out == 0 && m_in == 0) { // gain 1 -> no interpolation needed output_buffer.copyFrom(acn_out, 0, buffer, acn_in, 0, NumSamples); } else if (m_in < 0 && m_out < 0) { output_buffer.addFromWithRamp(acn_out, 0, buffer.getReadPointer(acn_in), NumSamples, _cos_z[-m_out], cos_z[-m_out]); // interpolation with ramp done by juce } else if (m_in < 0 && m_out > 0) { output_buffer.addFromWithRamp(acn_out, 0, buffer.getReadPointer(acn_in), NumSamples, -_sin_z[m_out], -sin_z[m_out]); } else if (m_in > 0 && m_out > 0) { output_buffer.addFromWithRamp(acn_out, 0, buffer.getReadPointer(acn_in), NumSamples, _cos_z[m_out], cos_z[m_out]); } else if (m_in > 0 && m_out < 0) { output_buffer.addFromWithRamp(acn_out, 0, buffer.getReadPointer(acn_in), NumSamples, _sin_z[m_in], sin_z[m_in]); } } } } // return output buffer buffer = output_buffer; }