jackpipe-dev / src / aat / AatFrequencyResponseLoop.h

/*
 * Copyright © 2011 Aleksey Kunitskiy <alexey.kv@gmail.com>
 * 
 * This file is part of JackPipe
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef _JackLoop_H_
#define _JackLoop_H_

#include <algorithm>
#include <iostream>

#include <jackaudioio.hpp>

#include "Util.h"
#include "AatExceptions.h"
#include "FftSineGenerator.h"
#include "LinearFftAnalizer.h"
#include "Vector.h"

namespace JackPipe {

namespace AAT {
    
template<typename T>
class AatFrequencyResponseLoop : public JackCpp::AudioIO {

  std::auto_ptr< JackPipe::FftSineGenerator<T> >  _lFftG;
  std::auto_ptr< JackPipe::LinearFftAnalizer<T> > _lFftA;
  std::auto_ptr< JackPipe::JackLoopBufferManager<T> > _jlbm;
  JackPipe::WindowingFunction<T>  _wF;
  
  typename JackPipe::Vector<T>::vec16_t _b;
  typename JackPipe::Vector<T>::vec16_t _ob;
  typename JackPipe::Vector<T>::vec16_t _fr;

  T _signalNormFactor;
  bool _rms;

  bool _verbose;
  std::ostream& _vOutput;

  unsigned _popSkip;

  float _obSizeParam;

  unsigned _jackPhysicalInPort;
  unsigned _jackPhysicalOutPort;

  protected:
    virtual int audioCallback(jack_nframes_t nframes, 
        audioBufVector inBufs,
        audioBufVector outBufs)
    {
      static int popBufferStatus = -1;
      static int pushBufferStatus = -1;

      if (_popSkip > 0)
      {
        // fill output with zeros to avoid nonzero data on input
        std::fill_n(outBufs[0], nframes, 0.0f);
        _popSkip--;
        return 0;
      }

      if (_rms)
      {
        popBufferStatus = _jlbm->pop(outBufs[0], nframes);
        if (popBufferStatus == JackPipe::JackLoopBufferManager<T>::ib_end)
          std::fill_n(outBufs[0], nframes, 0.0f);
        float rms = JackPipe::rmsPower<float>(inBufs[0], nframes);
        if (_verbose)
          _vOutput << "rms " << rms << std::endl;
        if (rms > _obSizeParam)
        {
          if (_verbose)
            _vOutput << "push ok" <<  std::endl;
          pushBufferStatus = _jlbm->push(inBufs[0], nframes);
          if (pushBufferStatus == JackPipe::JackLoopBufferManager<T>::ob_full)
          {
            if (_verbose)
              _vOutput << "ob_end" << std::endl;
            return 1;
          }
          return 0;
        }
        else if (pushBufferStatus != -1)
        {
          _jlbm->push(inBufs[0], nframes);
          return 1; // rms <= noise, maybe xrun
        }
        else return 0;
      }
      return 1;
    }

  public:
  AatFrequencyResponseLoop(
      const T f0,
      const T f1,
      const unsigned uB,
      const bool base2,
      std::string const& window,
      float obSizeParam,
      unsigned jackPhysicalInPort = 0,
      unsigned jackPhysicalOutPort = 0,
      bool rms = true,
      bool verbose = false,
      std::ostream& vOutput = std::cerr ) :
    JackCpp::AudioIO("AAT frequency response loop", 1, 1, false),
    _wF(window.c_str()),
    _rms(rms),
    _verbose(verbose),
    _vOutput(vOutput),
    _popSkip(5),
    _obSizeParam(obSizeParam),
    _jackPhysicalInPort(jackPhysicalInPort),
    _jackPhysicalOutPort(jackPhysicalOutPort)
  {
    _lFftG = std::auto_ptr< JackPipe::FftSineGenerator<T> >
      ( new JackPipe::FftSineGenerator<T>(f0, f1, getSampleRate(), uB, base2, getTime()) );
    _lFftA = std::auto_ptr< JackPipe::LinearFftAnalizer<T> >
      ( new JackPipe::LinearFftAnalizer<T>(*_lFftG) );
    _wF.pokeCache(_lFftG->getBufferSize());

    _lFftG->generateSignal(_b);
    _wF.apply(_b, _lFftG->getBufferSize());

    _signalNormFactor = 
      JackPipe::Vector<T>::normalize(_b, _lFftG->getBufferSize());

    if (rms)
    {
      _jlbm = std::auto_ptr< JackPipe::JackLoopBufferManager<T> >
        ( new JackPipe::JackLoopBufferManager<T>(_b, _ob, _lFftG->getBufferSize() + 4096u) );
    }
    else
    {
      unsigned obSize = static_cast<unsigned>
        ( static_cast<float>(_lFftG->getBufferSize()) * _obSizeParam + 0.5f );

      _jlbm = std::auto_ptr< JackPipe::JackLoopBufferManager<T> >
        ( new JackPipe::JackLoopBufferManager<T>(_b, _ob, obSize) );
    }
  }

  typename JackPipe::Vector<T>::vec16_t const&
    getFR() { return _fr; }

  unsigned getFRSize() { return _lFftA->getTransformSize(); }

  void run() {
    start();
    try {
      connectFromPhysical(0, _jackPhysicalInPort);
    }
    catch (std::range_error) {
      throw(invalidPort(numPhysicalSourcePorts()));
    }
    try {
      connectToPhysical(0, _jackPhysicalOutPort);
    }
    catch (std::range_error) {
      throw(invalidPort(numPhysicalDestinationPorts()));
    }
    wait();
    close();

    _lFftA->analize(_ob, _jlbm->getPushedSize());

    _lFftA->getResult(_fr);
    JackPipe::Vector<T>::scaleVecMul(_fr, _signalNormFactor / _wF.getDensityFactor());

    // debug stuff
    if (_verbose)
    {
      _vOutput << "buffer size " << _lFftG->getBufferSize() << std::endl;
      _vOutput << "pushed size " << _jlbm->getPushedSize() << std::endl;
    }
    //JackPipe::Vector<T>::saveAscii("b.dat", _b, _lFftG->getBufferSize());
    //JackPipe::Vector<T>::saveAscii("ob.dat", _ob, _jlbm->getPushedSize());
  }

};

} // AAT

} // JackPipe

#endif
//  vim:set ts=2 sw=2 tw=78 et:
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.