Commits

Aleksey Kunitskiy  committed 1337079

Initial commit

  • Participants

Comments (0)

Files changed (50)

+syntax: glob
+build/*	
+fftw++-*/*
+*.swp

File CMakeLists.txt

+cmake_minimum_required(VERSION 2.6)
+project(jackpipe C CXX)
+
+set(JACKPIPE_CXX_FLAGS "-O2 -pipe -ansi -Wall -pedantic -g"
+  CACHE STRING "JackPipe compiler flags")
+
+set(CMAKE_CXX_FLAGS "${JACKPIPE_CXX_FLAGS}" CACHE INTERNAL "not used")
+set(CMAKE_CXX_FLAGS_RELEASE "${JACKPIPE_CXX_FLAGS}" CACHE INTERNAL "not used")
+set(CMAKE_CXX_FLAGS_DEBUG "${JACKPIPE_CXX_FLAGS}" CACHE INTERNAL "not used")
+
+option(RTAAT "Build RealTime Audio Analisis Tool" OFF)
+option(AAT "Build Audio Analisis Tool" OFF)
+
+option(JACKPIPE_TEST "Enable testing framework" OFF)
+option(LOCALTEST "Enable local testing" OFF)
+option(FFTW_ALIGMENT_DEBUG "Turn off SIMD optimizations in fftw library
+and use unaligned buffers. Helps to debug overflow in buffers" OFF)
+option(DEBUG "Enable generic debugging code" OFF)
+option(USE_OPENMP "Check for OpenMP support" ON)
+
+if(USE_OPENMP)
+  set(CMAKE_CXX_FLAGS_TMP ${CMAKE_CXX_FLAGS})
+  set(CMAKE_CXX_FLAGS_RELEASE_TMP ${CMAKE_CXX_FLAGS_RELEASE})
+  set(CMAKE_CXX_FLAGS_DEBUG_TMP ${CMAKE_CXX_FLAGS_DEBUG})
+
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp")
+  set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fopenmp")
+  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fopenmp")
+
+  try_run(OMP_THREADS_DETECTED COMPILE_RESULT
+    ${CMAKE_CURRENT_BINARY_DIR}
+    ${CMAKE_SOURCE_DIR}/cmaketests/detect_openmp.cxx
+    )
+
+  if(OMP_THREADS_DETECTED EQUAL 1)
+    message(STATUS
+      "OpenMP is disabled (omp_detected_threads == ${OMP_THREADS_DETECTED})")
+    set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS_TMP})
+    set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE_TMP})
+    set(CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG_TMP})
+  else()
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp")
+    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fopenmp")
+    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fopenmp")
+    add_definitions("-DOMP_MAX_THREADS=${OMP_THREADS_DETECTED}")
+    add_definitions(-DOPENMP)
+    message(STATUS
+      "OpenMP is enabled (OMP_MAX_THREADS == ${OMP_THREADS_DETECTED})")
+  endif()
+endif()
+
+if(FFTW_ALIGMENT_DEBUG)
+  add_definitions(-DFFTW_ALIGMENT_DEBUG)
+  message(STATUS "FFTW aligment debugging is enabled")
+endif()
+
+if(DEBUG)
+  add_definitions(-DDEBUG)
+  message(STATUS "Generic debugging support is enabled")
+endif()
+
+add_definitions(-DSMP)
+
+find_package(PkgConfig)
+
+#pkg_check_modules(JACKPIPE_REQUIRED REQUIRED
+#  jack>=0.118
+#  jackcpp-0.3>=0.3.2
+#  tclap>=1.1.0
+#)
+
+pkg_check_modules(JACKPIPE_REQUIRED_FFTW REQUIRED
+  fftw3>=3.2
+  fftw3f>=3.2
+  fftw3l>=3.2
+)
+
+include_directories(${JACKPIPE_REQUIRED_INCLUDE_DIRS}
+  ${JACKPIPE_REQUIRED_FFTW_INCLUDE_DIRS})
+
+#add_subdirectory(src) 
+if(JACKPIPE_TEST)
+  add_subdirectory(test)
+endif()
+
+if(LOCALTEST)
+  add_subdirectory(localtest)
+endif()
+
+if(RTAAT)
+  add_subdirectory(src/rtaat)
+endif()
+if(AAT)
+  add_subdirectory(src/aat)
+endif()
+
+#  vim:set ts=2 sw=2 tw=78 et:

File cmaketests/FindQwt6.cmake

+# - Try to find the Qwt includes and library
+# which defines
+#
+# QWT_FOUND - system has Qwt
+# QWT_INCLUDE_DIR - where to find qwt.h
+# QWT_LIBRARIES - the libraries to link against to use Qwt
+# QWT_LIBRARY - where to find the Qwt library (not for general use)
+
+# copyright (c) 2006 Thomas Moenicke thomas.moenicke at kdemail.net
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+
+SET(QWT_NEED_VERSION 6)
+
+IF(NOT QT4_FOUND)
+    INCLUDE(FindQt4)
+ENDIF(NOT QT4_FOUND)
+
+SET(QWT_FOUND "NO")
+
+IF(QT4_FOUND)
+    FIND_PATH(QWT_INCLUDE_DIR qwt.h
+		/usr/local/qwt${QWT_NEED_VERSION}/include
+    /usr/local/include
+	/usr/include/qwt${QWT_NEED_VERSION}
+    /usr/include
+    )
+
+SET(QWT_NAMES ${QWT_NAMES} qwt${QWT_NEED_VERSION} libqwt${QWT_NEED_VERSION})
+    FIND_LIBRARY(QWT_LIBRARY
+        NAMES ${QWT_NAMES}
+        PATHS /usr/local/qwt/lib /usr/local/lib /usr/lib
+    )
+
+    IF (QWT_LIBRARY)
+
+        SET(QWT_LIBRARIES ${QWT_LIBRARY})
+        SET(QWT_FOUND "YES")
+
+        IF (CYGWIN)
+            IF(BUILD_SHARED_LIBS)
+            # No need to define QWT_USE_DLL here, because it's default for Cygwin.
+            ELSE(BUILD_SHARED_LIBS)
+            SET (QWT_DEFINITIONS -DQWT_STATIC)
+            ENDIF(BUILD_SHARED_LIBS)
+        ENDIF (CYGWIN)
+
+    ENDIF (QWT_LIBRARY)
+ENDIF(QT4_FOUND)
+
+IF (QWT_FOUND)
+  IF (NOT QWT_FIND_QUIETLY)
+	  MESSAGE(STATUS "Found Qwt${QWT_NEED_VERSION}: ${QWT_LIBRARY}")
+  ENDIF (NOT QWT_FIND_QUIETLY)
+ELSE (QWT_FOUND)
+  IF (QWT_FIND_REQUIRED)
+    MESSAGE(FATAL_ERROR "Could not find Qwt library")
+  ENDIF (QWT_FIND_REQUIRED)
+ENDIF (QWT_FOUND)
+
+MARK_AS_ADVANCED(QWT_INCLUDE_DIR QWT_LIBRARY)
+

File cmaketests/detect_openmp.cxx

+#if _OPENMP
+#include <omp.h>
+#endif
+
+int main(int argc, const char *argv[])
+{
+#if _OPENMP
+	return omp_get_max_threads(); 
+#else
+	return 1;
+#endif
+}

File localtest/CMakeLists.txt

+include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src)
+
+set(LOCALTEST_SRCS
+  localtest.cxx
+)
+
+add_executable(${PROJECT_NAME}_localtest ${LOCALTEST_SRCS})
+target_link_libraries(${PROJECT_NAME}_localtest)
+
+#  vim:set ts=2 sw=2 tw=78 et:

File localtest/localtest.cxx

+#include "AsyncStack.h"
+#include <vector>
+#include <list>
+#include <iostream>
+
+#include <omp.h>
+
+using namespace JackPipe;
+using namespace std;
+
+std::list<int*> cache;
+
+void consumer(AsyncStack<int> &q)
+{
+	while(true)
+	{
+		int* p = q.blockingGet();
+		if (p != 0)
+		{
+			#pragma omp critical(cache)
+			{
+					cache.push_back(p);
+			}
+		} else throw std::runtime_error("blockingPop returned null pointer");
+	}
+}
+
+void producer(AsyncStack<int> &q)
+{
+	while(true)
+	{
+		#pragma omp critical(cache)
+		{
+			if (!cache.empty())
+			{
+				int *p = cache.front();
+				if (p!=0)
+				{
+					q.put(cache.front());
+					cache.pop_front();
+				}
+			}
+		}
+	}
+}
+
+int main(int argc, const char *argv[])
+{
+	const unsigned N = 20u;
+	const unsigned T = 100;
+	AsyncStack< int > q(N);
+#pragma omp parallel num_threads(T)
+	{
+		int t = omp_get_thread_num();
+		(t%2 == 0) ? consumer(q) : producer(q);
+	}
+	return 0;
+}

File sandbox/dr.m

+function f = sinf (x_step)
+	step = 0:x_step*pi:2*pi;
+	f = [];
+	for k = step
+		ff = -cos(step) .- 2.*cos(2.*step .+ k);
+		f = [f;abs(ff)];
+	end
+end
+
+function f = sinf2 (k, x)
+	step = 0:x_step*pi:2*pi;
+	f = -cos(x) .- 2.*cos(2.*x .+ step(k));
+end
+
+function f = getx (x_step, k)
+	step = 0:x_step*pi:2*pi;
+	f = step(k);
+end
+
+a = sinf(0.01);
+[a, b] = min(a);
+getx(0.01, b)

File sandbox/wn.m

+function m = generate (length, ncomp)
+	m = unifrnd(-1.0, 1.0, length, ncomp);
+end
+
+g = generate(48000/20, 256);
+b = blackman(48000/20);
+
+b = [b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b];
+b = [b,b];
+b = [b,b];
+b = [b,b];
+b = [b,b];
+g = g.*b;
+
+f = abs(fft(g, [], 1))./(48000/20);
+
+
+fs = sum(f,2);
+
+save('data.dat', 'fs');
+

File src/AAlloc.h

+/*
+ * Copyright © 2010 Aleksey Kunitskiy <alexey.kv@gmail.com>
+ * 
+ * This file is part of AlignedAllocator
+ *
+ * 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 _ALIGNEDALLOCATOR_H_
+#define _ALIGNEDALLOCATOR_H_
+
+#include <map>
+#include <stdexcept>
+#include <new>
+
+namespace AAlloc {
+
+using std::size_t;
+using std::ptrdiff_t;
+
+template <typename T, const unsigned align> class AlignedAllocator;
+
+// void
+template <const unsigned align> class AlignedAllocator<void, align> {
+  public:
+    typedef void*       pointer;
+    typedef const void* const_pointer;
+    // reference to void members are impossible.
+    typedef void value_type;
+    template <class U> struct rebind { typedef AlignedAllocator<U, align>
+                                       other; };
+};
+
+template <typename T, const unsigned align = 16>
+class AlignedAllocator {
+
+  typedef std::map<std::ptrdiff_t, std::ptrdiff_t>::iterator ptrmap_it;
+
+  static  std::map<std::ptrdiff_t, std::ptrdiff_t> _ptrmap;
+
+#ifdef DEBUG
+  static  unsigned _reference_count;
+#endif // DEBUG
+
+  void erase(ptrmap_it it);
+
+  public:
+    typedef size_t    size_type;
+    typedef ptrdiff_t difference_type;
+    typedef T*        pointer;
+    typedef const T*  const_pointer;
+    typedef T&        reference;
+    typedef const T&  const_reference;
+    typedef T         value_type;
+    template <class U> struct rebind { typedef AlignedAllocator<U, align>
+                                   other; };
+
+    AlignedAllocator();
+    AlignedAllocator(const AlignedAllocator&);
+    ~AlignedAllocator();
+
+    pointer address(reference x) const { return &x; };
+    const_pointer address(const_reference x) const { return &x; };
+
+    pointer allocate(size_type,
+                 typename AlignedAllocator<void, align>::const_pointer hint = 0);
+    void deallocate(pointer p, size_type n);
+    size_type max_size() const throw() {
+      return size_type(-1) / sizeof(value_type);
+    };
+
+    void construct(pointer p, const_reference val);
+
+    void destroy(pointer p) { p->~T(); };
+
+};
+
+template <typename T, const unsigned align>
+std::map<ptrdiff_t, ptrdiff_t> AlignedAllocator<T, align>::_ptrmap;
+
+#ifdef DEBUG
+template <typename T, const unsigned align>
+unsigned AlignedAllocator<T, align>::_reference_count = 0;
+#endif // DEBUG
+
+template <typename T, const unsigned align>
+AlignedAllocator<T,align>::AlignedAllocator()
+{
+#ifdef DEBUG
+  if( (align & (align - 1)) != 0)
+    throw std::runtime_error("AlignedAllocator : AlignedAllocator() template parameter align is not power of two");
+#ifdef OPENMP
+  #pragma omp critical(ptrmap_modify)
+#endif // OPENMP
+  ++_reference_count;
+#endif // DEBUG
+}
+
+template <typename T, const unsigned align>
+AlignedAllocator<T,align>::AlignedAllocator(const AlignedAllocator&)
+{
+#ifdef DEBUG
+#ifdef OPENMP
+  #pragma omp critical(ptrmap_modify)
+#endif // OPENMP
+  ++_reference_count;
+#endif // DEBUG
+}
+
+template <typename T, const unsigned align>
+typename AlignedAllocator<T,align>::pointer AlignedAllocator<T,align>::allocate(
+                 size_type n,
+                 typename AlignedAllocator<void, align>::const_pointer hint)
+{
+  if (n > this->max_size())
+    throw std::bad_alloc();
+
+  ptrdiff_t op = reinterpret_cast<ptrdiff_t>(
+      ::operator new(n
+        * sizeof (T)
+        + static_cast<size_t>(align)
+        - static_cast<size_t>(1))
+      );
+  ptrdiff_t ap = (op + static_cast<ptrdiff_t>(align) - static_cast<ptrdiff_t>(1))
+    & ~(static_cast<ptrdiff_t>(align) - static_cast<ptrdiff_t>(1));
+
+#ifdef OPENMP
+  #pragma omp critical(ptrmap_modify)
+#endif // OPENMP
+  _ptrmap.insert( std::pair<ptrdiff_t, ptrdiff_t>(ap, op) );
+  return reinterpret_cast<pointer>(ap); 
+}
+
+template <typename T, const unsigned align>
+void AlignedAllocator<T, align>::erase(ptrmap_it it)
+{
+  pointer real_p = reinterpret_cast<pointer>(it->second);
+  ::operator delete(real_p);
+  _ptrmap.erase(it);
+}
+
+template <typename T, const unsigned align>
+void AlignedAllocator<T, align>::construct(pointer p, const_reference val)
+{
+#ifdef OPENMP
+  #pragma omp critical(ptrmap_modify)
+#endif // OPENMP
+  new(static_cast<void*>(p)) T(val); // placement new
+}
+template <typename T, const unsigned align>
+void AlignedAllocator<T, align>::deallocate(pointer p, size_type n)
+{
+  // p is not permitted to be a null pointer. 
+
+  ptrdiff_t _p = reinterpret_cast<ptrdiff_t>(p);
+#ifdef OPENMP
+  #pragma omp critical(ptrmap_modify)
+  {
+#endif // OPENMP
+    ptrmap_it p_it = _ptrmap.find(_p);
+    if (p_it != _ptrmap.end())
+    {
+      erase(p_it);
+    }
+#ifdef DEBUG
+      else
+        throw std::runtime_error("AlignedAllocator::deallocate : _ptrmap doesn't have mapped pointer");
+#endif // DEBUG
+#ifdef OPENMP
+  }
+#endif // OPENMP
+}
+
+template <typename T, const unsigned align>
+AlignedAllocator<T,align>::~AlignedAllocator()
+{
+#ifdef DEBUG
+#ifdef OPENMP
+  #pragma omp critical (ptrmap_modify)
+  {
+#endif // OPENMP
+    if ( _reference_count > 0 ) {
+      --_reference_count;
+    }
+    else {
+      if (!_ptrmap.empty())
+        throw std::runtime_error("AlignedAllocator::destructor : there was still allocated memory in the pool");
+    }
+#ifdef OPENMP
+  }
+#endif // OPENMP
+#endif // DEBUG
+}
+
+} // namespace AAlloc
+
+#endif
+//  vim:set ts=2 sw=2 tw=78 et:

File src/AsyncContainer.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 _AsyncContainer_H_
+#define _AsyncContainer_H_
+
+#include <stdexcept>
+
+#include "PthCond.h"
+#include "PthMutex.h"
+#include "ScopedMutex.h"
+
+namespace JackPipe {
+
+  template<typename T, template<typename P> class Container>
+  class AsyncContainer {
+   
+    typedef T*  pointer;
+    typedef T&  reference;
+
+    typedef Container<pointer> container;
+
+    typedef ScopedMutex<PthMutex> PthScopedMutex;
+
+    PthMutex _modifyLock;
+    PthCond _freeCond;
+
+    pointer _buffer;
+    container _container;
+
+    const unsigned _capacity;
+    unsigned _n;
+
+    inline pointer atomicPop()
+    {
+      --_n;
+      return _container.atomicPop();
+    }
+
+    inline bool checkPointer(pointer p)
+    {
+      for (pointer a = _buffer; a != _buffer + _capacity; ++a)
+        if (a == p) return true;
+      return false;
+    }
+
+    public:
+      AsyncContainer(unsigned n) : _capacity(n), _n(n)
+      {
+        _buffer = new T[n];
+        while (n-- != 0u) _container.push(_buffer+n);
+      }
+
+      pointer get()
+      {
+        PthScopedMutex __sm(_modifyLock);
+        if (_n > 0)
+          return atomicPop();
+        else
+          return 0;
+      }
+
+      pointer blockingGet()
+      {
+        PthScopedMutex __sm(_modifyLock);
+        while(_n == 0) _freeCond.wait(_modifyLock);
+        return atomicPop();
+      }
+
+      bool empty() { return _container.empty(); }
+
+      void put(pointer e)
+      {
+        if (!checkPointer(e))
+          throw std::runtime_error("JackPipe::AsyncContainer::push :: pointer is not owned by this container");
+        PthScopedMutex __sm(_modifyLock);
+        if (_n < _capacity)
+        {
+          _container.push(e);
+          ++_n;
+          _freeCond.signal();
+        }
+        else
+        {
+          throw std::runtime_error("JackPipe::AsyncContainer::push :: trying to push above container capacity");
+        }
+      }
+
+      ~AsyncContainer() { delete [] _buffer; }
+  };
+
+} // JackPipe
+	
+#endif
+//  vim:set ts=2 sw=2 tw=78 et:

File src/AsyncQueue.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 _AsyncQueue_H_
+#define _AsyncQueue_H_
+
+#include <queue>
+
+#include "AsyncContainer.h"
+
+namespace JackPipe {
+
+  namespace Helper {
+
+    template<typename T>
+    class QueueWrapper : public std::queue<T> {
+
+      public:
+
+        T atomicPop()
+        {
+          T tmp = std::queue<T>::front();
+          std::queue<T>::pop();
+          return tmp;
+        }
+    };
+
+  }
+
+  template<typename T>
+  class AsyncQueue : public AsyncContainer< T, Helper::QueueWrapper >
+  {
+    public:
+      AsyncQueue(const unsigned n = 10u) : AsyncContainer<T, Helper::QueueWrapper>(n) {}
+  };
+
+} // JackPipe
+	
+#endif
+//  vim:set ts=2 sw=2 tw=78 et:

File src/AsyncStack.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 _AsyncStack_H_
+#define _AsyncStack_H_
+
+#include <stack>
+
+#include "AsyncContainer.h"
+
+namespace JackPipe {
+
+  namespace Helper {
+
+    template<typename T>
+    class StackWrapper : public std::stack<T>
+    {
+      public:
+        T atomicPop()
+        {
+          T tmp = std::stack<T>::top();
+          std::stack<T>::pop();
+          return tmp;
+        }
+    };
+
+  }
+
+  template<typename T>
+  class AsyncStack : public AsyncContainer< T, Helper::StackWrapper >
+  {
+    public:
+      AsyncStack(const unsigned n = 10u) : AsyncContainer<T, Helper::StackWrapper>(n) {}
+  };
+
+
+} // JackPipe
+	
+#endif
+//  vim:set ts=2 sw=2 tw=78 et:

File src/CMakeLists.txt

+set(JACKPIPE_SOURCES
+  FftwWrapper.cxx
+  main.cxx
+)
+
+add_executable(${PROJECT_NAME} ${JACKPIPE_SOURCES})
+target_link_libraries(${PROJECT_NAME} ${JACKPIPE_REQUIRED_LIBRARIES}
+  ${JACKPIPE_REQUIRED_FFTW_LIBRARIES})
+
+#  vim:set ts=2 sw=2 tw=78 et:

File src/CpuID.cxx

+/*
+ * 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/>.
+ */
+
+#include "CpuID.h"
+
+namespace JackPipe {
+
+int CpuID::_ff_ecx = 0;
+int CpuID::_ff_edx = 0;
+
+CpuID::CpuID()
+{
+  asm (
+      "movl $1, %%eax;"
+      "cpuid;"
+      "movl %%ecx, %0;"
+      "movl %%edx, %1;"
+      :"=m"(_ff_ecx),"=m"(_ff_edx)
+      ::"%eax","%ebx","%ecx","edx"
+  );
+}
+
+namespace {
+  CpuID __cpuID;
+}
+
+} // JackPipe
+  
+//  vim:set ts=2 sw=2 tw=78 et:
+/*
+ * 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 _CpuID_H_
+#define _CpuID_H_
+
+namespace JackPipe {
+
+  class CpuID {
+    static int _ff_ecx;
+    static int _ff_edx;
+
+    const static int _sse = 1<<25;
+    const static int _sse2 = 1<<26;
+    const static int _sse3 = 1;
+    const static int _ssse3 = 1<<9;
+    const static int _sse41 = 1<<19;
+    const static int _sse42 = 1<<20;
+
+    public:
+      CpuID ();
+
+      static bool hasSSE () {
+        return static_cast<bool>(_ff_edx & _sse);
+      };
+      static bool hasSSE2 () {
+        return static_cast<bool>(_ff_edx & _sse2);
+      };
+      static bool hasSSE3 () {
+        return static_cast<bool>(_ff_ecx & _sse3);
+      };
+      static bool hasSSSE3 () {
+        return static_cast<bool>(_ff_ecx & _ssse3);
+      };
+      static bool hasSSE41 () {
+        return static_cast<bool>(_ff_ecx & _sse41);
+      };
+      static bool hasSSE42 () {
+        return static_cast<bool>(_ff_ecx & _sse42);
+      };
+  };
+  
+} // JackPipe
+  
+#endif // _CpuID_H_
+
+//  vim:set ts=2 sw=2 tw=78 et:

File src/FftSineGenerator.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 _FftSineGenerator_H_
+#define _FftSineGenerator_H_
+
+#include <algorithm>
+#include <memory>
+#include <stdexcept>
+#include "Vector.h"
+#include "LinearSineGenerator.h"
+#include "FftwWrapper.h"
+
+namespace JackPipe {
+
+template<typename T>
+class FftSineGenerator : public LinearSineGenerator<T> {
+
+  typedef SignalGenerator<T> sg_t;
+
+  FftwWrapper<T> _FftW;
+
+  typename Vector<T>::vec16c_t _fvDftIn;
+  typename Vector<T>::vec16_t _fvDftOut;
+
+  void packPhaseShifts(typename Vector<T>::vec16c_t &p);
+  void packPhaseShifts(typename Vector<T>::vec16c_t &p,
+      typename Vector<T>::vec16_t const& amp);
+
+public:
+
+  FftSineGenerator(const T f0, const T f1,
+      const T fSr, const unsigned uB,
+      bool bFreqBase2 = false, const long lRs = 0, bool bRoundUp = true)
+    throw(std::invalid_argument);
+  virtual ~FftSineGenerator() {}
+
+  virtual void generateSignal(typename Vector<T>::vec16_t &v, bool normalize = false) throw(std::runtime_error);
+  virtual void generateSignal(typename Vector<T>::vec16_t &v,
+      typename Vector<T>::vec16_t const& amp, bool normalize = false) throw(std::runtime_error);
+
+};
+  
+template<typename T>
+FftSineGenerator<T>::FftSineGenerator(
+    const T f0, const T f1,
+    const T fSr, const unsigned uB,
+    bool bFreqBase2, const long lRs, bool bRoundUp)
+  throw(std::invalid_argument)
+  : LinearSineGenerator<T>(f0, f1, fSr, uB, bFreqBase2, lRs, bRoundUp)
+{
+  // TODO: as signal generation is't done too often this
+  // can be implemented as in-place transform with phase shifts packing
+  // on each generateSignal call
+
+  int fftwOpts = FftwWrapper<T>::destroyInput
+                  | FftwWrapper<T>::estimate ; // FIXME
+
+  _FftW.init_1d(_fvDftIn, _fvDftOut, sg_t::_uBlockSize, fftwOpts );
+}
+
+template<typename T>
+void FftSineGenerator<T>::packPhaseShifts(typename Vector<T>::vec16c_t &p)
+{
+  T normFactor = _FftW.getNormFactor();
+  for(unsigned i = 0; i < LinearSineGenerator<T>::_uFreqCount; i++)
+  {
+    //p[0] is the DC component and must be 0
+    p[i+1] = std::complex<T>(
+        std::sin(LinearSineGenerator<T>::_fvPhaseShifts[i]) / normFactor,
+        -std::cos(LinearSineGenerator<T>::_fvPhaseShifts[i]) / normFactor );
+  }
+}
+
+//FIXME: reuse code from generateSignal(std::vector, bool)
+template<typename T>
+void FftSineGenerator<T>::packPhaseShifts(
+    typename Vector<T>::vec16c_t &p,
+    typename Vector<T>::vec16_t const &amp )
+{
+  T normFactor = _FftW.getNormFactor();
+  for(unsigned i = 0; i < LinearSineGenerator<T>::_uFreqCount; i++)
+  {
+    //p[0] is the DC component and must be 0
+    p[i+1] = std::complex<T>(
+        amp[i] * std::sin(LinearSineGenerator<T>::_fvPhaseShifts[i]) / normFactor,
+        -amp[i] * std::cos(LinearSineGenerator<T>::_fvPhaseShifts[i]) / normFactor );
+  }
+}
+
+template<typename T>
+void FftSineGenerator<T>::generateSignal(
+    typename Vector<T>::vec16_t &v, bool normalize)
+throw(std::runtime_error)
+{
+  packPhaseShifts(_fvDftIn);
+  _FftW.execute();
+
+  Vector<T>::resizeIfLess(v, FftSineGenerator<T>::getBufferSize());
+
+  if (normalize)
+  {
+    T max = static_cast<T>(0.0);
+    for(unsigned i = 0; i < LinearSineGenerator<T>::_uBlockSize; i++)
+    {
+      T a = std::abs(_fvDftOut[i]);
+      if(a > max)
+        max = a;
+    }
+    Vector<T>::scaleVecDiv(_fvDftOut, max);
+  }
+
+  growVector(_fvDftOut, v, LinearSineGenerator<T>::_uBlockCount);
+}
+
+template<typename T>
+void FftSineGenerator<T>::generateSignal(
+    typename Vector<T>::vec16_t &v,
+    typename Vector<T>::vec16_t const &amp,
+    bool normalize)
+throw(std::runtime_error)
+{
+  packPhaseShifts(_fvDftIn, amp);
+  _FftW.execute();
+
+  Vector<T>::resizeIfLess(v, FftSineGenerator<T>::getBufferSize());
+
+  if (normalize)
+  {
+    T max = static_cast<T>(0.0);
+    for(unsigned i = 0; i < LinearSineGenerator<T>::_uBlockSize; i++)
+    {
+      T a = std::abs(_fvDftOut[i]);
+      if(a > max)
+        max = a;
+    }
+    Vector<T>::scaleVecDiv(_fvDftOut, max);
+  }
+
+  growVector(_fvDftOut, v, LinearSineGenerator<T>::_uBlockCount);
+}
+
+} // JackPipe
+
+#endif
+//  vim:set ts=2 sw=2 tw=78 et:

File src/FftwWrapper.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 _FftwWrapper_H_
+#define _FftwWrapper_H_
+
+#include <vector>
+#include <complex>
+#include <stdexcept>
+#include <ostream>
+#include <istream>
+
+#include <fftw3.h>
+
+#include "AAlloc.h"
+#include "Misc.h"
+#include "Vector.h"
+
+#if SMP
+#include "Mutex.h"
+#include "ScopedMutex.h"
+#endif
+
+#define FFTWW_ENABLE_IF(condType, retType) \
+  template<class W> \
+  static typename \
+    EnableIf< IsTypeOf<W, condType>::value, retType>::value
+
+#define FFTWW_ENABLE_IF_VOID(condType) FFTWW_ENABLE_IF(condType, void)
+
+#define FFTWW_ENABLE_IF_NOSTATIC(condType, retType) \
+  template<class W> \
+  typename \
+    EnableIf< IsTypeOf<W, condType>::value, retType>::value
+
+#define FFTWW_ENABLE_IF_VOID_NOSTATIC(condType) FFTWW_ENABLE_IF_NOSTATIC(condType, void)
+
+namespace JackPipe {
+
+namespace FftwWrapperStatic {
+  static void fftwWriteCharToStream(char c, void* data) {
+    reinterpret_cast<std::ostream*>(data)->put(c);
+  }
+  static int fftwReadCharFromStream(void* data) {
+    return reinterpret_cast<std::istream*>(data)->get();
+  }
+
+  FFTWW_ENABLE_IF_VOID_NOSTATIC(float)
+    fftwLoadWisdom(std::istream& s) throw()
+    { fftwf_import_wisdom(&fftwReadCharFromStream, &s); }
+  FFTWW_ENABLE_IF_VOID_NOSTATIC(double)
+    fftwLoadWisdom(std::istream& s) throw()
+    { fftw_import_wisdom(&fftwReadCharFromStream, &s); }
+  FFTWW_ENABLE_IF_VOID_NOSTATIC(long double)
+    fftwLoadWisdom(std::istream& s) throw()
+    { fftwl_import_wisdom(&fftwReadCharFromStream, &s); }
+
+  FFTWW_ENABLE_IF_VOID_NOSTATIC(float)
+    fftwSaveWisdom(std::ostream& s) throw()
+    { fftwf_export_wisdom(&fftwWriteCharToStream, &s); }
+  FFTWW_ENABLE_IF_VOID_NOSTATIC(double)
+    fftwSaveWisdom(std::ostream& s) throw()
+    { fftw_export_wisdom(&fftwWriteCharToStream, &s); }
+  FFTWW_ENABLE_IF_VOID_NOSTATIC(long double)
+    fftwSaveWisdom(std::ostream& s) throw()
+    { fftwl_export_wisdom(&fftwWriteCharToStream, &s); }
+
+} // FftwWrapperStatic
+  
+template<typename T>
+class FftwWrapper {
+  IsSubsetOf<T, float, double, long double> __isFloatingPointCheck;
+
+  typedef typename If< IsTypeOf<T, float>::value,
+    fftwf_plan,
+    typename If< IsTypeOf<T, double>::value, fftw_plan, fftwl_plan>::value
+      >::value fftw_plan_t;
+  typedef typename If< IsTypeOf<T, float>::value,
+    fftwf_complex,
+    typename If< IsTypeOf<T, double>::value, fftw_complex, fftwl_complex>::value
+      >::value fftw_complex_t;
+
+  FFTWW_ENABLE_IF_VOID(float)
+    execute(fftw_plan_t p) throw() { fftwf_execute(p); }
+  FFTWW_ENABLE_IF_VOID(double)
+    execute(fftw_plan_t p) throw() { fftw_execute(p); }
+  FFTWW_ENABLE_IF_VOID(long double)
+    execute(fftw_plan_t p) throw() { fftwl_execute(p); }
+
+  FFTWW_ENABLE_IF_VOID(float)
+    fftwDestroyPlan(fftw_plan_t p) throw() { fftwf_destroy_plan(p); }
+  FFTWW_ENABLE_IF_VOID(double)
+    fftwDestroyPlan(fftw_plan_t p) throw() { fftw_destroy_plan(p); }
+  FFTWW_ENABLE_IF_VOID(long double)
+    fftwDestroyPlan(fftw_plan_t p) throw() { fftwl_destroy_plan(p); }
+
+  FFTWW_ENABLE_IF(float, fftw_plan_t)
+      fftwPlanDftReal_1d(unsigned N, float &in, fftwf_complex &out, int options) throw()
+      { return fftwf_plan_dft_r2c_1d(N, &in, &out, options); }
+  FFTWW_ENABLE_IF(double, fftw_plan_t)
+      fftwPlanDftReal_1d(unsigned N, double &in, fftw_complex &out, int options) throw()
+      { return fftw_plan_dft_r2c_1d(N, &in, &out, options); }
+  FFTWW_ENABLE_IF(long double, fftw_plan_t)
+      fftwPlanDftReal_1d(unsigned N, long double &in, fftwl_complex &out, int options) throw()
+      { return fftwl_plan_dft_r2c_1d(N, &in, &out, options); }
+  FFTWW_ENABLE_IF(float, fftw_plan_t)
+      fftwPlanDftReal_1d(unsigned N, fftwf_complex &in, float &out, int options) throw()
+      { return fftwf_plan_dft_c2r_1d(N, &in, &out, options); }
+  FFTWW_ENABLE_IF(double, fftw_plan_t)
+      fftwPlanDftReal_1d(unsigned N, fftw_complex &in, double &out, int options) throw()
+      { return fftw_plan_dft_c2r_1d(N, &in, &out, options); }
+  FFTWW_ENABLE_IF(long double, fftw_plan_t)
+      fftwPlanDftReal_1d(unsigned N, fftwl_complex &in, long double &out, int options) throw()
+      { return fftwl_plan_dft_c2r_1d(N, &in, &out, options); }
+
+  T forwardNormFactor(const unsigned N) const throw()
+    { return static_cast<T>(N) / static_cast<T>(2.0); }
+
+  T backwardNormFactor(const unsigned N) const throw()
+    { return static_cast<T>(2.0); }
+
+  fftw_plan_t _plan;
+  T _normFactor;
+
+#if SMP
+  static Mutex _mutex;
+#endif
+
+  FftwWrapper& operator=(const FftwWrapper& rhs) {}
+
+  public:
+
+  typedef typename Vector<T>::vec16_t vec16_t;
+  typedef typename Vector<T>::vec16c_t vec16c_t;
+
+    struct fftwPlanException : public std::runtime_error {
+      explicit fftwPlanException() :
+        std::runtime_error("Error: plan == 0") {} };
+
+    enum {
+      preserveInput = FFTW_PRESERVE_INPUT,
+      destroyInput = FFTW_DESTROY_INPUT,
+      measure = FFTW_MEASURE,
+      estimate = FFTW_ESTIMATE,
+      patient = FFTW_PATIENT,
+      exhaustive = FFTW_EXHAUSTIVE,
+      wisdomOnly = FFTW_WISDOM_ONLY
+    };
+
+    FftwWrapper() : _plan(0), _normFactor(static_cast<T>(0.0)) {}
+
+    // 1d r2c/c2r out-of-place transforms
+    FftwWrapper(vec16_t &in, vec16c_t &out, const unsigned N, const int options = 0)
+      throw(fftwPlanException)
+    {
+      init_1d(in, out, N, options);
+    }
+
+    FftwWrapper(vec16c_t &in, vec16_t &out, const unsigned N, const int options = 0)
+      throw(fftwPlanException)
+    {
+      init_1d(in, out, N, options);
+    }
+
+    void init_1d(vec16_t &in, vec16c_t &out, const unsigned N, const int options = 0)
+    {
+      Vector<T>::resizeIfLess(in, N);
+      Vector<T>::resizeIfLess(out, (N>>1u)+1u);
+      {
+        SCOPEDMUTEX_SMP(Mutex,_mutex);
+        _plan = fftwPlanDftReal_1d<T>(N, in[0],
+            reinterpret_cast<fftw_complex_t&>(out[0]), options);
+      }
+      if (_plan == 0)
+        throw fftwPlanException();
+      _normFactor = forwardNormFactor(N);
+    }
+
+    void init_1d(vec16c_t &in, vec16_t &out, const unsigned N, const int options = 0)
+    {
+      Vector<T>::resizeIfLess(in, (N>>1u)+1u);
+      Vector<T>::resizeIfLess(out, N);
+      {
+        SCOPEDMUTEX_SMP(Mutex,_mutex);
+        _plan = fftwPlanDftReal_1d<T>
+          (N, reinterpret_cast<fftw_complex_t&>(in[0]), out[0], options);
+      }
+      if (_plan == 0)
+        throw fftwPlanException();
+      _normFactor = backwardNormFactor(N);
+    }
+
+
+    // TODO: in-place transforms needs testing
+    //1d r2c/c2r in-place transform
+    // forward
+    FftwWrapper(vec16_t &inout, const unsigned N, const int options = 0)
+      throw(fftwPlanException)
+    {
+      init_1d(inout, N, options);
+    }
+
+    // backward
+    FftwWrapper(vec16c_t &inout, const unsigned N, const int options = 0)
+      throw(fftwPlanException)
+    {
+      init_1d(inout, N, options);
+    }
+
+    void init_1d(vec16_t &inout, const unsigned N, const int options = 0)
+    {
+      Vector<T>::resizeIfLess(inout, ((N>>1u)+1u)<<1u);
+      {
+        SCOPEDMUTEX_SMP(Mutex,_mutex);
+        _plan = fftwPlanDftReal_1d<T>
+          (N,
+           inout[0],
+           reinterpret_cast<fftw_complex_t&>(inout[0]),
+           options );
+      }
+      if (_plan == 0)
+        throw fftwPlanException();
+      _normFactor = forwardNormFactor(N);
+    }
+
+    void init_1d(vec16c_t &inout, const unsigned N, const int options = 0)
+      throw(fftwPlanException)
+    {
+      Vector<T>::resizeIfLess(inout, (N>>1u)+1u);
+      {
+        SCOPEDMUTEX_SMP(Mutex,_mutex);
+        _plan = fftwPlanDftReal_1d<T>
+          (N,
+           reinterpret_cast<fftw_complex_t&>(inout[0]),
+           inout[0],
+           options);
+      }
+      if (_plan == 0)
+        throw fftwPlanException();
+      _normFactor = backwardNormFactor(N);
+    }
+
+    ~FftwWrapper() throw() {
+      destroy();
+    }
+
+    void destroy() {
+      SCOPEDMUTEX_SMP(Mutex,_mutex);
+      fftwDestroyPlan<T>(_plan);
+    }
+
+    T getNormFactor()
+    { return _normFactor; }
+
+#ifndef DEBUG
+    void execute() throw() { execute<T>(_plan); }
+#else
+    void execute() throw(fftwPlanException) {
+      _plan == 0
+        ? throw fftwPlanException()
+        : execute<T>(_plan);
+    }
+#endif
+
+};
+
+#if SMP
+  template<typename T> Mutex FftwWrapper<T>::_mutex;
+#endif
+
+} // JackPipe
+
+#endif
+//  vim:set ts=2 sw=2 tw=78 et:

File src/JackLoopBufferManager.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 _JackLoopBufferManager_H_
+#define _JackLoopBufferManager_H_
+
+#include <memory>
+#include "Vector.h"
+
+namespace JackPipe {
+  
+template<typename pushT, typename popT = pushT>
+class JackLoopBufferManager {
+  typedef typename Vector<popT>::vec16_t::const_iterator  constIterator;
+  typedef typename Vector<pushT>::vec16_t::iterator       iterator;
+
+  constIterator _ib;
+  iterator _ob;
+
+  constIterator _ibCurrent;
+  iterator _obCurrent;
+
+  unsigned _writtenOut;
+  unsigned _readIn;
+
+  unsigned _obSize;
+  unsigned _ibSize;
+
+  unsigned _partialPushSize;
+  unsigned _partialPopSize;
+
+  public:
+  JackLoopBufferManager(
+      typename Vector<popT>::vec16_t const& ib,
+      typename Vector<pushT>::vec16_t &ob,
+      unsigned obSize)
+    : _ib(ib.begin()), _ibCurrent(ib.begin()),
+    _writtenOut(0), _readIn(0),
+    _obSize(obSize), _ibSize(ib.size()),
+    _partialPushSize(0), _partialPopSize(0)
+  {
+    Vector<pushT>::resizeIfLess(ob, _obSize);
+    _obCurrent = _ob = ob.begin();
+  }
+
+  enum status_t {
+    pp_success,
+    ob_partially_filled,
+    ob_full,
+    ib_partially_filled,
+    ib_end,
+    pp_error
+  };
+
+  unsigned getPushPartialFillSize() { return _partialPushSize; }
+  unsigned getPopPartialFillSize() { return _partialPopSize; }
+  unsigned getPushedSize() { return _writtenOut; }
+  unsigned getPoppedSize() { return _readIn; }
+
+  template<typename InputIterator>
+  int push(InputIterator i, const unsigned n)
+  {
+    if (_writtenOut < _obSize - n)
+    {
+      _obCurrent = std::copy(i, i+n, _obCurrent);
+      _writtenOut += n;
+      return pp_success;
+    }
+    else if (_writtenOut < _obSize)
+    {
+      _partialPushSize = _obSize - _writtenOut;
+      _obCurrent = std::copy(i, i + _partialPushSize, _obCurrent);
+      _writtenOut = _obSize;
+      return ob_partially_filled;
+    }
+    else if (_writtenOut == _obSize)
+      return ob_full;
+    return pp_error;
+  }
+
+  template<typename OutputIterator>
+  int pop(OutputIterator o, const unsigned n)
+  {
+    if (_readIn < _ibSize - n)
+    {
+      std::copy(_ibCurrent, _ibCurrent + n, o);
+      _readIn += n;
+      _ibCurrent += n;
+      return pp_success;
+    }
+    else if (_readIn < _ibSize)
+    {
+      _partialPopSize = _ibSize - _readIn;
+      std::copy(_ibCurrent, _ibCurrent + _partialPopSize, o);
+      std::fill_n(o+_partialPopSize, n - _partialPopSize, static_cast<popT>(0.0));
+      _readIn = _ibSize;
+      _ibCurrent += (_ibSize - _readIn);
+      return ib_partially_filled;
+    }
+    else if (_readIn == _ibSize)
+      return ib_end;
+    return pp_error;
+  }
+
+  void reset() { 
+    _ibCurrent = _ib; _obCurrent = _ob;
+    _readIn = _writtenOut = 0;
+    _partialPushSize = _partialPopSize = 0;
+  }
+
+};
+
+} // JackPipe
+	
+#endif
+//  vim:set ts=2 sw=2 tw=78 et:

File src/LinearAnalizer.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 _LinearAnalizer_H_
+#define _LinearAnalizer_H_
+
+#include "Vector.h"
+#include "LinearSineGenerator.h"
+
+namespace JackPipe {
+  
+template<typename T>
+class LinearAnalizer {
+  protected:
+    LinearSineGenerator<T> const& _lsg;
+
+  public:
+    template<typename M>
+    LinearAnalizer(LinearSineGenerator<M> const& lsg) : _lsg(lsg) {}
+
+    virtual void analize(typename Vector<T>::vec16_t const& v, unsigned N) = 0;
+    virtual ~LinearAnalizer() {};
+};
+
+} // JackPipe
+	
+#endif
+//  vim:set ts=2 sw=2 tw=78 et:

File src/LinearFftAnalizer.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 _LinearFftAnalizer_H_
+#define _LinearFftAnalizer_H_
+
+#include <algorithm>
+
+#ifdef OPENMP
+  #undef OPENMP // code is not complete
+#endif
+
+#if OPENMP
+#include <omp.h>
+#include "OmpScopedMutex.h"
+#endif
+
+#include "Vector.h"
+#include "FftwWrapper.h"
+#include "SignalGenerator.h"
+#include "LinearSineGenerator.h"
+#include "LinearAnalizer.h"
+
+namespace JackPipe {
+  
+template<typename T>
+class LinearFftAnalizer : public LinearAnalizer<T> {
+
+#if OPENMP
+  const unsigned localMaxThreads = OMP_MAX_THREADS;
+  
+  FftwWrapper<T> _FftwV[localMaxThreads];
+  typename Vector<T>::vec16_t _IOBufV[localMaxThreads];
+
+  unsigned _M, _currentBlock, _totalBlocks;
+  typename Vector<T>::vec16_t::const_iterator _inputMarker;
+
+  static omp_lock_t _processLock;
+  static omp_lock_t _analizeLock;
+  static omp_lock_t _popBlockLock;
+#else
+  FftwWrapper<T> _FftW;
+  typename Vector<T>::vec16_t _IOBuf;
+#endif
+
+  typename Vector<T>::vec16_t _resultBuf;
+
+#if OPENMP
+  void processBlock(typename Vector<T>::vec16_t &iobuf) { 
+    _FftW.execute();
+    OmpScopedMutex sm(_processLock);
+    Vector<T>::vecAdd(_resultBuf, iobuf);
+  }
+
+  void pushInputBuffer(typename Vector<T>::vec16_t &v, unsigned N) {
+    N = N > 0 ? N : v.size();
+    _M = N % LinearAnalizer<T>::_lsg.getBlockSize();
+    _totalBlocks = N / LinearAnalizer<T>::_lsg.getBlockSize() + (_M > 0 ? 1u : 0);
+    _currentBlock = 0;
+  }
+
+  bool popBlock(typename Vector<T>::vec16_t &iobuf) {
+    _popBlockLock.lock();
+    if (_currentBlock == _totalBlocks)
+      return false;
+    if (_currentBlock == 0)
+    {
+      ++_currentBlock;
+      typename Vector<T>::vec16_t::const_iterator __inputMarker = _inputMarker;
+      _inputMarker += M/2u;
+      _popBlockLock.unlock();
+      typename Vector<T>::vec16_t::iterator outputMarker = iobuf.begin();
+      unsigned fillSize = LinearAnalizer<T>::_lsg.getBlockSize() - M/2u;
+      std::fill_n(outputMarker, fillSize, static_cast<T>(0.0));
+      std::copy(__inputMarker, __inputMarker + M/2u, outputMarker + fillSize);
+      return true;
+    }
+    else
+    {
+      _popBlockLock.lock();
+      if (_currentBlock < _totalBlocks - 1u)
+      {
+        ++_currentBlock;
+        typename Vector<T>::vec16_t::const_iterator __inputMarker = _inputMarker;
+        _inputMarker += LinearAnalizer<T>::_lsg.getBlockSize();
+        _popBlockLock.unlock();
+        std::copy(__inputMarker,
+            __inputMarker + LinearAnalizer<T>::_lsg.getBlockSize(),
+            iobuf.begin() );
+        return true;
+      }
+      else
+      {
+        unsigned fillSize = M - M/2u;
+        outputMarker = std::copy(inputMarker,
+                          inputMarker + fillSize,
+                          _IOBuf.begin() );
+        std::fill(outputMarker, _IOBuf.end(), static_cast<T>(0.0));
+      }
+    }
+  }
+#else
+  void processBlock() { 
+    _FftW.execute();
+    Vector<T>::vecAdd(_resultBuf, _IOBuf);
+  }
+#endif
+
+  void resetResultBuffer() { 
+    std::fill(_resultBuf.begin(), _resultBuf.end(), static_cast<T>(0.0));
+  }
+
+  public:
+    LinearFftAnalizer(LinearSineGenerator<T> const& lsg)
+      : LinearAnalizer<T>(lsg)
+    {
+      _FftW.init_1d(_IOBuf, lsg.getBlockSize());
+      _resultBuf.resize(_IOBuf.size());
+    }
+
+    virtual void analize(typename Vector<T>::vec16_t const& v, unsigned N = 0);
+    unsigned getTransformSize() { return _resultBuf.size() / 2u - 1u; }
+    unsigned getResult(typename Vector<T>::vec16_t &v);
+
+    virtual ~LinearFftAnalizer() {};
+};
+
+template<typename T>
+unsigned LinearFftAnalizer<T>::getResult(
+    typename Vector<T>::vec16_t &v)
+{
+  Vector<T>::resizeIfLess(v, getTransformSize());
+  for (unsigned i = 2u; i < _resultBuf.size(); i += 2u )
+  {
+    v[i/2u-1u] = std::sqrt(_resultBuf[i] * _resultBuf[i] + _resultBuf[i+1u] * _resultBuf[i+1u]);
+  }
+  return _resultBuf.size() / 2u - 1u;
+}
+
+template<typename T>
+void LinearFftAnalizer<T>::analize(
+    typename Vector<T>::vec16_t const& v,
+    unsigned N )
+{
+  N = N > 0 ? N : v.size();
+  unsigned M = N % LinearAnalizer<T>::_lsg.getBlockSize();
+  unsigned blocks = N / LinearAnalizer<T>::_lsg.getBlockSize() + (M > 0 ? 1u : 0);
+
+  typename Vector<T>::vec16_t::const_iterator inputMarker = v.begin();
+
+  if (M == 0)
+  {
+    for (unsigned i = 0; i < blocks; i++)
+    {
+      std::copy(inputMarker,
+          inputMarker + LinearAnalizer<T>::_lsg.getBlockSize(),
+          _IOBuf.begin() );
+      processBlock();
+      inputMarker += LinearAnalizer<T>::_lsg.getBlockSize();
+    }
+  }
+  else
+  {
+    typename Vector<T>::vec16_t::iterator outputMarker = _IOBuf.begin();
+    unsigned fillSize = LinearAnalizer<T>::_lsg.getBlockSize() - M/2u;
+
+    std::fill_n(outputMarker, fillSize, static_cast<T>(0.0));
+    std::copy(inputMarker, inputMarker + M/2u, outputMarker + fillSize);
+    inputMarker += M/2u;
+
+    for (unsigned i = 1u; i < blocks; i++)
+    {
+      std::copy(inputMarker,
+          inputMarker + LinearAnalizer<T>::_lsg.getBlockSize(),
+          _IOBuf.begin() );
+      processBlock();
+      inputMarker += LinearAnalizer<T>::_lsg.getBlockSize();
+    }
+
+    fillSize = M - M/2u;
+    outputMarker = std::copy(inputMarker,
+                      inputMarker + fillSize,
+                      _IOBuf.begin() );
+    std::fill(outputMarker, _IOBuf.end(), static_cast<T>(0.0));
+    processBlock();
+  }
+
+  Vector<T>::scaleVecDiv(_resultBuf,
+      _FftW.getNormFactor() * static_cast<T>(M > 0 ? blocks - 1u : blocks));
+}
+
+#if OPENMP
+template<typename T>
+omp_lock_t LinearFftAnalizer<T>::_processLock;
+template<typename T>
+omp_lock_t LinearFftAnalizer<T>::_analizeLock;
+#endif
+	
+} // JackPipe
+
+#endif
+//  vim:set ts=2 sw=2 tw=78 et:

File src/LinearSineGenerator.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 _LinearSineGenerator_H_
+#define _LinearSineGenerator_H_
+
+#include <cstdlib>
+#include <cmath>
+#include <stdexcept>
+#include "Vector.h"
+#include "SignalGenerator.h"
+
+namespace JackPipe {
+
+template<typename T>
+class LinearSineGenerator : public SignalGenerator<T> {
+
+  typedef SignalGenerator<T> sg_t;
+  
+protected:
+  void generateRandPhaseShifts(typename Vector<T>::vec16_t &v);
+
+  T _f1;
+  unsigned _uBlockCount;
+  unsigned _uFreqCount;
+  long _lRandomSeed;
+
+  typename Vector<T>::vec16_t _fvPhaseShifts;
+
+public:
+  LinearSineGenerator(const T f0, const T f1,
+      const T fSr, const unsigned uB,
+      bool bFreqBase2 = false, const long lRs = 0, bool bRoundUp = true)
+    throw(std::invalid_argument);
+  virtual ~LinearSineGenerator () {};
+
+  virtual void generateSignal(typename Vector<T>::vec16_t &v, bool normalize = false) throw(std::runtime_error);
+  virtual void generateSignal(typename Vector<T>::vec16_t &v,
+      typename Vector<T>::vec16_t const& amp, bool normalize = false);
+
+  T getf1() const { return _f1; }
+  unsigned getBufferSize() const { return sg_t::_uBlockSize * _uBlockCount; }
+  unsigned getBlockCount() const { return _uBlockCount; }
+  unsigned getFreqCount() const { return _uFreqCount; }
+
+  typename Vector<T>::vec16_t const&
+    getPhaseShifts() const { return _fvPhaseShifts; }
+};
+  
+template<typename T>
+LinearSineGenerator<T>::LinearSineGenerator(
+    const T f0, const T f1,
+    const T fSr, const unsigned uB,
+    bool bFreqBase2, const long lRs, bool bRoundUp)
+  throw(std::invalid_argument)
+  : SignalGenerator<T>(f0, fSr,
+      bFreqBase2 == true
+        ? SignalGenerator<T>::base2Approx
+        : SignalGenerator<T>::aligned4Approx,
+        bRoundUp)
+{
+  if (f0 > f1)
+    throw (std::invalid_argument("f0 must be less than f1"));
+  if ((fSr / static_cast<T>(2.0)) < f1)
+    throw (std::invalid_argument("f1 must be less than nyquist frequency"));
+  
+  _f1 = f1;
+  _uBlockCount = uB;
+  _lRandomSeed = lRs;
+
+  _uFreqCount = static_cast<unsigned>(_f1 * static_cast<T>(sg_t::_uBlockSize) / sg_t::_fSr);
+
+  generateRandPhaseShifts(_fvPhaseShifts);
+}
+
+template<typename T>
+void LinearSineGenerator<T>::generateRandPhaseShifts(typename Vector<T>::vec16_t &v)
+{
+  Vector<T>::resizeIfLess(v, _uFreqCount);
+
+  srand(_lRandomSeed);
+
+  for (unsigned i = 0; i < _uFreqCount; i++)
+  {
+    T d = 
+      static_cast<T>(rand())
+      / static_cast<T>(RAND_MAX);
+    v[i] = 
+      static_cast<T>(2.0)
+      * static_cast<T>(M_PI)
+      * d;
+  }
+}
+
+template<typename T>
+void LinearSineGenerator<T>::generateSignal(
+    typename Vector<T>::vec16_t &v,
+    bool normalize )
+throw(std::runtime_error)
+{
+  Vector<T>::resizeIfLess(v, getBufferSize());
+
+  T max = static_cast<T>(0.0);
+  T bs = static_cast<T>(sg_t::_uBlockSize);
+  for (unsigned i = 0; i < sg_t::_uBlockSize; i++)
+  {
+    v[i] = static_cast<T>(0.0);
+    T ii = static_cast<T>(i) / bs;
+    for (unsigned j = 0; j < _uFreqCount; j++)
+    {
+      v[i] += std::sin(
+          static_cast<T>(2.0)
+          * static_cast<T>(M_PI)
+          * static_cast<T>(j+1)
+          * ii
+          + _fvPhaseShifts[j] );
+    }
+    //FIXME: don't compute normalization
+    //       constant if normalize == false
+    //       probably compiler can optimize this
+    //       in compile time, but who knows...
+    if (normalize && std::abs(v[i]) > max)
+      max = std::abs(v[i]);
+  }
+
+  if (normalize)
+    Vector<T>::scaleVecDiv(v, max, sg_t::_uBlockSize);
+
+  growVector(v, _uBlockCount);
+}
+
+//FIXME: reuse code from generateSignal(std::vector, bool)
+template<typename T>
+void LinearSineGenerator<T>::generateSignal(typename Vector<T>::vec16_t &v,
+      typename Vector<T>::vec16_t const &amp, bool normalize)
+{
+  Vector<T>::resizeIfLess(v, getBufferSize());
+
+  T max = static_cast<T>(0.0);
+  T bs = static_cast<T>(sg_t::_uBlockSize);
+  for (unsigned i = 0; i < sg_t::_uBlockSize; i++)
+  {
+    v[i] = static_cast<T>(0.0);
+    T ii = static_cast<T>(i) / bs;
+    for (unsigned j = 0; j < _uFreqCount; j++)
+    {
+      v[i] += amp[j]*std::sin(
+          static_cast<T>(2.0)
+          * static_cast<T>(M_PI)
+          * static_cast<T>(j+1)
+          * ii
+          + _fvPhaseShifts[j] );
+    }
+    //FIXME: don't compute normalization
+    //       constant if normalize == false
+    //       probably compiler can optimize this
+    //       in compile time, but who knows...
+    if (normalize && std::abs(v[i]) > max)
+      max = std::abs(v[i]);
+  }
+
+  if (normalize)
+    Vector<T>::scaleVecDiv(v, max, sg_t::_uBlockSize);
+
+  growVector(v, _uBlockCount);
+}
+
+} // JackPipe
+
+#endif
+//  vim:set ts=2 sw=2 tw=78 et:
+/*
+ * 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 _Misc_H_
+#define _Misc_H_
+
+#include <stdexcept>
+
+namespace JackPipe {
+
+  //{{{ IsTypeOf
+  template<typename T1, typename T2>
+  struct IsTypeOf {
+    const static bool value = false;
+  };
+
+  template<typename T>
+  struct IsTypeOf<T, T> {
+    const static bool value = true;
+  };
+  //}}}
+
+  //{{{ If
+  template<bool Cond, typename TrueResult, typename FalseResult>
+  struct If;
+
+  template<typename TrueResult, typename FalseResult>
+  struct If<true, TrueResult, FalseResult> {
+    typedef TrueResult value;
+  };
+
+  template<typename TrueResult, typename FalseResult>
+  struct If<false, TrueResult, FalseResult> {
+    typedef FalseResult value;
+  };
+  // }}}
+
+  //{{{ Template type subset
+  template<typename T, typename A, typename B, typename C>
+  struct IsSubsetOf {
+//    static void constraints(T* p, A* pp) { A* pT = p; }
+//    static void constraints(T* p, B* pp) { B* pT = p; }
+//    static void constraints(T* p, C* pp) { C* pT = p; }
+//    IsSubsetOf() { void(*p)(T*, T*) = constraints; }
+  };
+  //}}}
+
+  //{{{ Enable if
+  template <bool, typename T = void> struct EnableIf {};
+  template <typename T> struct EnableIf<true, T> { typedef T value; };
+  //}}}
+  
+
+  //{{{ TypeSelector
+  template<char t>
+  struct TypeSelector {
+    TypeSelector() throw(std::runtime_error)
+    { throw std::runtime_error("RuntimeTypeSelector: undefined floating point type"); }
+  };
+
+#ifdef FLOAT
+  template<>
+  struct TypeSelector<'f'> {
+    typedef float Type;
+    TypeSelector() throw() {}
+    const char* getTypeName() { return "float"; }
+  };
+#endif
+
+#ifdef DOUBLE
+  template<>
+  struct TypeSelector<'d'> {
+    typedef double Type;
+    TypeSelector() throw() {}
+    const char* getTypeName() { return "double"; }
+  };
+#endif
+
+#if LONG_DOUBLE
+  template<>
+  struct TypeSelector<'L'> {
+    typedef long double Type;
+    TypeSelector() throw() {}
+    const char* getTypeName() { return "long double"; }
+  };
+#endif
+  //}}}
+} // JackPipe
+	
+#endif
+//  vim:set ts=2 sw=2 tw=78 et:
+/*
+ * 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 _Mutex_H_
+#define _Mutex_H_
+
+#if OPENMP
+#include "OmpMutex.h"
+#define Mutex OmpMutex
+#else
+#include "PthMutex.h"
+#define Mutex PthMutex
+#endif
+	
+#endif
+//  vim:set ts=2 sw=2 tw=78 et:

File src/OmpMutex.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 _OmpMutex_H_
+#define _OmpMutex_H_
+
+#include <omp.h>
+
+namespace JackPipe {
+  struct OmpMutex {
+
+    OmpMutex() { omp_init_lock(&_lock); }
+
+    ~OmpMutex() { omp_destroy_lock(&_lock); }
+
+    int lock() { omp_set_lock(&_lock); return 0; }
+
+    int trylock() { return omp_test_lock(&_lock); }
+
+    int unlock() { omp_unset_lock(&_lock); return 0; }
+
+    protected:
+
+      omp_lock_t _lock;
+  };
+} // JackPipe
+	
+#endif
+//  vim:set ts=2 sw=2 tw=78 et:

File src/PthCond.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.