/*
 *
 *    soniK digital audio editor
 *    Copyright (C) 2003-2006  Robert Walker <rob@tenfoot.org.uk>
 *
 *    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 2 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, write to the Free Software
 *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
#ifndef SONIK_UTIL_H
#define SONIK_UTIL_H

#include "sonik_types.h"

#include <qstring.h>

#include <cmath>

namespace Sonik
{
  template <typename T>
  inline T bound(const T x, const T min, const T len)
  {
    if (x < min || len == 0)
      return min;
    else if (x > min+len-1)
      return min+len-1;
    else
      return x;
  }

  template <typename T>
  inline T to(const Sample val)
  {
    if (val < -1.0f)
      return SampleTraits<T>::min();
    else if (val > 1.0f)
      return SampleTraits<T>::max();
    else
      return SampleTraits<T>::cast(val);
  }

  template <typename T>
  inline void to(T* dest, const Sample* src, size_t len)
  {
    while (len--)
    {
      *dest = Sonik::to<T>(*src);
      src++;
      dest++;
    }
  }

  template <>
  inline void to<Sample>(Sample* dest, const Sample* src, size_t len)
  {
    memcpy(dest, src, len*sizeof(Sample));
  }

  template <typename T>
  inline Sample from(const T val)
  {
    return val / SampleTraits<T>::range();
  }

  template <typename T>
  inline void from(Sample* dest, const T* src, size_t len)
  {
    while (len--)
    {
      *dest = Sonik::from<T>(*src);
      src++;
      dest++;
    }
  }

  template <>
  inline void from<Sample>(Sample* dest, const Sample* src, size_t len)
  {
    memcpy(dest, src, len*sizeof(Sample));
  }

  template <typename T>
  void interleave(auto_buffer<Sample>& in, auto_buffer<T>& out,
                  size_t stride, size_t offset)
  {
    assert(out.capacity() >= in.size() * stride);
    out.resize(in.size() * stride);

    Sample* src = in.data();
    T* dst = out.data() + offset;
    for ( ; src != in.end(); ++src, dst += stride)
      *dst = to<T>(*src);
  }

  template <typename T>
  void deinterleave(auto_buffer<T>& in, auto_buffer<Sample>& out,
                    size_t stride, size_t offset)
  {
    assert(out.capacity() >= in.size() / stride);
    out.resize(in.size() / stride);

    T* src = in.data() + offset;
    Sample* dst = out.data();
    for ( ; dst != out.end(); src += stride, ++dst)
      *dst = from<T>(*src);
  }

  inline int hour(int t, uint sampleRate)
  {
    return t / (sampleRate*60*60);
  }

  inline int minute(int t, uint sampleRate)
  {
    return (t % (sampleRate*60*60)) / (sampleRate*60);
  }

  inline int sec(int t, uint sampleRate)
  {
    return (t % (sampleRate*60)) / sampleRate;
  }

  inline int msec(int t, uint sampleRate)
  {
    return (t % sampleRate) * 1000 / sampleRate;
  }

  inline int CDDAFrame(int t, uint sampleRate)
  {
    return (t % sampleRate) * 75 / sampleRate;
  }

  inline int PALFrame(int t, uint sampleRate)
  {
    return (t % sampleRate) * 25 / sampleRate;
  }

  inline int NTSCFrame(int t, uint sampleRate)
  {
    return (int)((t % sampleRate) * 29.97 / sampleRate);
  }

  inline int toMSecs(int t, uint sampleRate)
  {
    // compute seconds & milli-seconds separately to avoid overflow
    return (t / sampleRate) * 1000 + msec(t, sampleRate);
  }

  int timeToSamples(uint sampleRate, int h, int m, int s=0, int ms=0);

  inline int secondsToSamples(uint sampleRate, double s=0.0f)
  {
    return lrint(s * sampleRate);
  }

  QString toString(int t, uint sampleRate, TimeFormat format);

  // longest time string in a file of length t samples
  QString widestFormatString(int t, uint sampleRate, TimeFormat format);

  inline int screenToTime(int screenPos, int screenStart, float zoom)
  {
    return screenStart + (int)(0.5 + screenPos / zoom);
  }

  inline int timeToScreenL(int time, int screenStart, float zoom)
  {
    return (int)((time - screenStart) * zoom - (zoom > 1.0 ? zoom/2 : 0));
  }

  inline int timeToScreenM(int time, int screenStart, float zoom)
  {
    return (int)((time - screenStart) * zoom);
  }

  inline int timeToScreenU(int time, int screenStart, float zoom)
  {
    return (int)((time - screenStart) * zoom + (zoom > 1.0 ? (zoom/2 - 1) : 0));
  }

  inline float valTodB(float r)
  {
    return 20.0f * std::log10(r);
  }

  inline float dBToVal(float db)
  {
    return std::pow(10.0f, (db*0.05f));
  }

  template <typename T>
  inline QValueVector<T> sequence(const T start, const T end, const T step=(T)1)
  {
    QValueVector<T> res;
    for (T i = start ; i < end; i += step)
      res.push_back(i);
    return res;
  }

}

#endif // SONIK_UTIL_H
