<commit_before>/*
  NUI3 - C++ cross-platform GUI framework for OpenGL based applications
  Copyright (C) 2002-2003 Sebastien Metrot

  licence: see nui3/LICENCE.TXT
*/

#include "nui.h"
#include "nuiKnob.h"
#include "nuiDrawContext.h"
#include "nuiXML.h"

#if (defined (TARGET_IPHONE_SIMULATOR) || defined (TARGET_OS_IPHONE))
nuiSize nuiKnob::mDefaultSensitivity = 4;
#else
nuiSize nuiKnob::mDefaultSensitivity = 10;
#endif
nuiSize nuiKnob::mDefaultFineSensitivityRatio = 10;
nglKeyCode nuiKnob::mDefaultFineSensitivityKey = NK_LSHIFT;

nuiKnob::nuiKnob(const nuiRange& rRange)
  : nuiSimpleContainer(),
    mKnobSink(this)
{
  if (SetObjectClass(_T("nuiKnob")))
    InitAttributes();
  Init(rRange);
}

nuiKnob::nuiKnob(const nuiRange& rRange, nuiImageSequence* pImageSequence)
: nuiSimpleContainer(),
mKnobSink(this)
{
  if (SetObjectClass(_T("nuiKnob")))
    InitAttributes();
  Init(rRange);
  SetImageSequence(pImageSequence);
}

void nuiKnob::Init(const nuiRange& rRange)
{
  mRange = rRange;
  mpImageSequence = NULL;

  mClicked = false;
  mRange.SetPageSize(0);
  mFrameIndex = 0;

  mSensitivity = mDefaultSensitivity;
  mFineSensitivityRatio = mDefaultFineSensitivityRatio;
  mFineSensitivityKey = mDefaultFineSensitivityKey;

  mKnobSink.Connect(mRange.Changed, &nuiKnob::DoInvalidate);
  //mKnobSink.Connect(mRange.ValueChanged, &nuiKnob::DoInvalidate);
  NUI_ADD_EVENT(ValueChanged);
  NUI_ADD_EVENT(InteractiveValueChanged);

  mSequenceNeedRefresh = false;
  mSequenceNbFrames = 0;
  mSequenceOrientation = "Vertical";

}

void nuiKnob::InitAttributes()
{
  nuiAttribute<const nglPath&>* AttributeTexture = new nuiAttribute<const nglPath&>
  (nglString(_T("Sequence")), nuiUnitNone,
   nuiMakeDelegate(this, &nuiKnob::GetSequencePath),
   nuiMakeDelegate(this, &nuiKnob::SetSequencePath));

  nuiAttribute<uint32>* AttributeNbFrames = new nuiAttribute<uint32>
  (nglString(_T("NbFrames")), nuiUnitNone,
   nuiAttribute<uint32>::GetterDelegate(this, &nuiKnob::GetNbFrames),
   nuiAttribute<uint32>::SetterDelegate(this, &nuiKnob::SetNbFrames));

  nuiAttribute<nglString>* AttributeOrientation = new nuiAttribute<nglString>
  (nglString(_T("Orientation")), nuiUnitNone,
   nuiAttribute<nglString>::GetterDelegate(this, &nuiKnob::GetOrientation),
   nuiAttribute<nglString>::SetterDelegate(this, &nuiKnob::SetOrientation));

  AddAttribute(AttributeTexture);
  AddAttribute(AttributeNbFrames);
  AddAttribute(AttributeOrientation);

}

// attributes
const nglPath& nuiKnob::GetSequencePath()
{
  return mpImageSequence->GetTexturePath();
}

void nuiKnob::SetSequencePath(const nglPath& rPath)
{
  mSequencePath = rPath;
  mSequenceNeedRefresh = true;
  nuiEvent event;
  DoInvalidate(event);
}

nglString nuiKnob::GetOrientation()
{
  return mpImageSequence->GetOrientation();
}

void nuiKnob::SetOrientation(nglString orientation)
{
  mSequenceOrientation = orientation;
  mSequenceNeedRefresh = true;
  nuiEvent event;
  DoInvalidate(event);
}

uint32 nuiKnob::GetNbFrames()
{
  return mpImageSequence->GetNbFrames();
}

void nuiKnob::SetNbFrames(uint32 nbFrames)
{
  mSequenceNbFrames = nbFrames;
  mSequenceNeedRefresh = true;
  nuiEvent event;
  DoInvalidate(event);
}

bool nuiKnob::Load(const nuiXMLNode* pNode)
{
  nuiSimpleContainer::Load(pNode);

  SetObjectClass(_T("nuiKnob"));
  mKnobSink.SetTarget(this);
  mClicked = false;
  mInteractiveValueChanged = false;

  mSensitivity = mDefaultSensitivity;
  mFineSensitivityRatio = mDefaultFineSensitivityRatio;
  mFineSensitivityKey = mDefaultFineSensitivityKey;

  // FIXME: interpret other attributes...
  mKnobSink.Connect(mRange.Changed, &nuiKnob::DoInvalidate);
  //mKnobSink.Connect(mRange.ValueChanged, &nuiKnob::DoInvalidate);
  NUI_ADD_EVENT(ValueChanged);
  NUI_ADD_EVENT(InteractiveValueChanged);

  return true;
}

nuiXMLNode* nuiKnob::Serialize(nuiXMLNode* pParentNode, bool Recursive) const
{
  nuiXMLNode* pNode = nuiWidget::Serialize(pParentNode,true);
  if (!pNode)
    return NULL;

  return pNode;
}

nuiKnob::~nuiKnob()
{
}

void nuiKnob::SetImageSequence(nuiImageSequence* pImageSequence)
{
  mpImageSequence = pImageSequence;
}

nuiImageSequence* nuiKnob::GetImageSequence()
{
  return mpImageSequence;
}

// Received Mouse events:
bool nuiKnob::MouseClicked  (nuiSize X, nuiSize Y, nglMouseInfo::Flags Button)
{
  mClickX = X;
  mClickY = Y;

  if (Button & nglMouseInfo::ButtonLeft)
  {
    mClicked = true;
    Grab();
    Invalidate();
    mClickValue = mRange.GetValue();

    return true;
  }
  else if (Button & nglMouseInfo::ButtonWheelUp)
  {
    if (IsKeyDown(mFineSensitivityKey))
    {
      mRange.SetValue(mRange.GetValue() + mRange.GetIncrement() / mFineSensitivityRatio);
    }
    else
    {
      mRange.Increment();
    }
    ActivateToolTip(this, true);
    return true;
  }
  else if (Button & nglMouseInfo::ButtonWheelDown)
  {
    if (IsKeyDown(mFineSensitivityKey))
    {
      mRange.SetValue(mRange.GetValue() - mRange.GetIncrement() / mFineSensitivityRatio);
    }
    else
    {
      mRange.Decrement();
    }
    ActivateToolTip(this, true);
    return true;
  }
  return false;
}

bool nuiKnob::MouseUnclicked  (nuiSize X, nuiSize Y, nglMouseInfo::Flags Button)
{
  if (mInteractiveValueChanged)
    ValueChanged();
  mInteractiveValueChanged = false;

  if (Button & nglMouseInfo::ButtonLeft)
  {
    mClicked = false;

    Ungrab();

    Invalidate();
    return true;
  }
  return false;
}

bool nuiKnob::MouseMoved(nuiSize X, nuiSize Y)
{
  if (mClicked)
  {
    nuiSize sensitivity = mSensitivity;
    if (IsKeyDown(mFineSensitivityKey))
    {
      sensitivity *= mFineSensitivityRatio;
    }

    nuiSize x,y;
    nuiSize range = sqrtf(GetRect().GetWidth() * GetRect().GetHeight());
    x = X-mClickX;
    y = mClickY - Y;

    //nuiSize length = range;
    nuiSize start= mClickValue;
    nuiSize movement = ( x + y ) / sensitivity;

    start += (mRange.GetRange() - mRange.GetPageSize()) * (movement/range);

    mRange.SetValue(start);

    mInteractiveValueChanged = true;
    InteractiveValueChanged();

    // Rotate the contained widget if there is only one:
    /* unused: nuiWidget* pItem = NULL; */

    long count = mpChildren.size();
    if (!count)
      return true;

    return true;
  }

  return false;
}

// Data management:
bool nuiKnob::HandlePageDown(const nuiEvent& rEvent)
{
  mRange.PageIncrement();
  return false;
}

bool nuiKnob::HandlePageUp(const nuiEvent& rEvent)
{
  mRange.PageDecrement();
  return false;
}

nuiRange& nuiKnob::GetRange()
{
  return mRange;
}

bool nuiKnob::DoInvalidate(const nuiEvent& rEvent)
{
  if (mSequenceNeedRefresh)
  {
    delete mpImageSequence;
    mpImageSequence = NULL;

    mpImageSequence = new nuiImageSequence();
    mpImageSequence->SetNbFrames(mSequenceNbFrames);
    mpImageSequence->SetTexturePath(mSequencePath);
    mpImageSequence->SetOrientation(mSequenceOrientation);
    mSequenceNeedRefresh = false;
  }

  Invalidate();
  return false;
}

nuiRect nuiKnob::CalcIdealSize()
{
  if (mpChildren.empty())
  {
    if (!mpImageSequence)
      return nuiRect(0,0,0,0);

    const nuiRect& rect = mpImageSequence->GetIdealRect();
    return rect;
  }
  else
  {
    return nuiSimpleContainer::CalcIdealSize();
  }
}

bool nuiKnob::SetRect(const nuiRect& rRect)
{
  nuiWidget::SetRect(rRect);
  mpImageSequence->SetLayout(rRect);
  return true;
}

bool nuiKnob::Draw(nuiDrawContext* pContext)
{
  if (mpImageSequence)
  {
    mFrameIndex = (int)((mpImageSequence->GetNbFrames()-1) * (mRange.GetValue() - mRange.GetMinimum())) / (mRange.GetMaximum() - mRange.GetMinimum());

    mpImageSequence->SetFrameIndex(mFrameIndex);
    mpImageSequence->Draw(pContext, this);
  }

  return nuiSimpleContainer::Draw(pContext);

}

void nuiKnob::SetDefaultSensitivity(nuiSize DefaultSensitivity)
{
  mDefaultSensitivity = DefaultSensitivity;
}

void nuiKnob::SetSensitivity(nuiSize Sensitivity)
{
  mSensitivity = Sensitivity;
}

// the bigger the ratio is, the slower the knob will turn.
void nuiKnob::SetDefaultFineSensitivityRatio(nuiSize DefaultFineSensitivityRatio)
{
  mDefaultFineSensitivityRatio = DefaultFineSensitivityRatio;
}

void nuiKnob::SetFineSensitivityRatio(nuiSize FineSensitivityRatio)
{
  mFineSensitivityRatio = FineSensitivityRatio;
}

void nuiKnob::SetDefaultFineSensitivityKey(nglKeyCode DefaultFineSensitivityKey)
{
  mDefaultFineSensitivityKey = DefaultFineSensitivityKey;
}

void nuiKnob::SetFineSensitivityKey(nglKeyCode FineSensitivityKey)
{
  mFineSensitivityKey = FineSensitivityKey;
}

<commit_msg>nuiKnob updated: don't catch double-click<commit_after>/*
  NUI3 - C++ cross-platform GUI framework for OpenGL based applications
  Copyright (C) 2002-2003 Sebastien Metrot

  licence: see nui3/LICENCE.TXT
*/

#include "nui.h"
#include "nuiKnob.h"
#include "nuiDrawContext.h"
#include "nuiXML.h"

#if (defined (TARGET_IPHONE_SIMULATOR) || defined (TARGET_OS_IPHONE))
nuiSize nuiKnob::mDefaultSensitivity = 4;
#else
nuiSize nuiKnob::mDefaultSensitivity = 10;
#endif
nuiSize nuiKnob::mDefaultFineSensitivityRatio = 10;
nglKeyCode nuiKnob::mDefaultFineSensitivityKey = NK_LSHIFT;

nuiKnob::nuiKnob(const nuiRange& rRange)
  : nuiSimpleContainer(),
    mKnobSink(this)
{
  if (SetObjectClass(_T("nuiKnob")))
    InitAttributes();
  Init(rRange);
}

nuiKnob::nuiKnob(const nuiRange& rRange, nuiImageSequence* pImageSequence)
: nuiSimpleContainer(),
mKnobSink(this)
{
  if (SetObjectClass(_T("nuiKnob")))
    InitAttributes();
  Init(rRange);
  SetImageSequence(pImageSequence);
}

void nuiKnob::Init(const nuiRange& rRange)
{
  mRange = rRange;
  mpImageSequence = NULL;

  mClicked = false;
  mRange.SetPageSize(0);
  mFrameIndex = 0;

  mSensitivity = mDefaultSensitivity;
  mFineSensitivityRatio = mDefaultFineSensitivityRatio;
  mFineSensitivityKey = mDefaultFineSensitivityKey;

  mKnobSink.Connect(mRange.Changed, &nuiKnob::DoInvalidate);
  //mKnobSink.Connect(mRange.ValueChanged, &nuiKnob::DoInvalidate);
  NUI_ADD_EVENT(ValueChanged);
  NUI_ADD_EVENT(InteractiveValueChanged);

  mSequenceNeedRefresh = false;
  mSequenceNbFrames = 0;
  mSequenceOrientation = "Vertical";

}

void nuiKnob::InitAttributes()
{
  nuiAttribute<const nglPath&>* AttributeTexture = new nuiAttribute<const nglPath&>
  (nglString(_T("Sequence")), nuiUnitNone,
   nuiMakeDelegate(this, &nuiKnob::GetSequencePath),
   nuiMakeDelegate(this, &nuiKnob::SetSequencePath));

  nuiAttribute<uint32>* AttributeNbFrames = new nuiAttribute<uint32>
  (nglString(_T("NbFrames")), nuiUnitNone,
   nuiAttribute<uint32>::GetterDelegate(this, &nuiKnob::GetNbFrames),
   nuiAttribute<uint32>::SetterDelegate(this, &nuiKnob::SetNbFrames));

  nuiAttribute<nglString>* AttributeOrientation = new nuiAttribute<nglString>
  (nglString(_T("Orientation")), nuiUnitNone,
   nuiAttribute<nglString>::GetterDelegate(this, &nuiKnob::GetOrientation),
   nuiAttribute<nglString>::SetterDelegate(this, &nuiKnob::SetOrientation));

  AddAttribute(AttributeTexture);
  AddAttribute(AttributeNbFrames);
  AddAttribute(AttributeOrientation);

}

// attributes
const nglPath& nuiKnob::GetSequencePath()
{
  return mpImageSequence->GetTexturePath();
}

void nuiKnob::SetSequencePath(const nglPath& rPath)
{
  mSequencePath = rPath;
  mSequenceNeedRefresh = true;
  nuiEvent event;
  DoInvalidate(event);
}

nglString nuiKnob::GetOrientation()
{
  return mpImageSequence->GetOrientation();
}

void nuiKnob::SetOrientation(nglString orientation)
{
  mSequenceOrientation = orientation;
  mSequenceNeedRefresh = true;
  nuiEvent event;
  DoInvalidate(event);
}

uint32 nuiKnob::GetNbFrames()
{
  return mpImageSequence->GetNbFrames();
}

void nuiKnob::SetNbFrames(uint32 nbFrames)
{
  mSequenceNbFrames = nbFrames;
  mSequenceNeedRefresh = true;
  nuiEvent event;
  DoInvalidate(event);
}

bool nuiKnob::Load(const nuiXMLNode* pNode)
{
  nuiSimpleContainer::Load(pNode);

  SetObjectClass(_T("nuiKnob"));
  mKnobSink.SetTarget(this);
  mClicked = false;
  mInteractiveValueChanged = false;

  mSensitivity = mDefaultSensitivity;
  mFineSensitivityRatio = mDefaultFineSensitivityRatio;
  mFineSensitivityKey = mDefaultFineSensitivityKey;

  // FIXME: interpret other attributes...
  mKnobSink.Connect(mRange.Changed, &nuiKnob::DoInvalidate);
  //mKnobSink.Connect(mRange.ValueChanged, &nuiKnob::DoInvalidate);
  NUI_ADD_EVENT(ValueChanged);
  NUI_ADD_EVENT(InteractiveValueChanged);

  return true;
}

nuiXMLNode* nuiKnob::Serialize(nuiXMLNode* pParentNode, bool Recursive) const
{
  nuiXMLNode* pNode = nuiWidget::Serialize(pParentNode,true);
  if (!pNode)
    return NULL;

  return pNode;
}

nuiKnob::~nuiKnob()
{
}

void nuiKnob::SetImageSequence(nuiImageSequence* pImageSequence)
{
  mpImageSequence = pImageSequence;
}

nuiImageSequence* nuiKnob::GetImageSequence()
{
  return mpImageSequence;
}

// Received Mouse events:
bool nuiKnob::MouseClicked  (nuiSize X, nuiSize Y, nglMouseInfo::Flags Button)
{
  mClickX = X;
  mClickY = Y;

  if ((Button & nglMouseInfo::ButtonLeft) && (Button & nglMouseInfo::ButtonDoubleClick))
  {
    return false;
  }
  else if (Button & nglMouseInfo::ButtonLeft)
  {
    mClicked = true;
    Grab();
    Invalidate();
    mClickValue = mRange.GetValue();

    return true;
  }
  else if (Button & nglMouseInfo::ButtonWheelUp)
  {
    if (IsKeyDown(mFineSensitivityKey))
    {
      mRange.SetValue(mRange.GetValue() + mRange.GetIncrement() / mFineSensitivityRatio);
    }
    else
    {
      mRange.Increment();
    }
    ActivateToolTip(this, true);
    return true;
  }
  else if (Button & nglMouseInfo::ButtonWheelDown)
  {
    if (IsKeyDown(mFineSensitivityKey))
    {
      mRange.SetValue(mRange.GetValue() - mRange.GetIncrement() / mFineSensitivityRatio);
    }
    else
    {
      mRange.Decrement();
    }
    ActivateToolTip(this, true);
    return true;
  }
  return false;
}

bool nuiKnob::MouseUnclicked  (nuiSize X, nuiSize Y, nglMouseInfo::Flags Button)
{
  if (mInteractiveValueChanged)
    ValueChanged();
  mInteractiveValueChanged = false;

  if (Button & nglMouseInfo::ButtonLeft)
  {
    mClicked = false;

    Ungrab();

    Invalidate();
    return true;
  }
  return false;
}

bool nuiKnob::MouseMoved(nuiSize X, nuiSize Y)
{
  if (mClicked)
  {
    nuiSize sensitivity = mSensitivity;
    if (IsKeyDown(mFineSensitivityKey))
    {
      sensitivity *= mFineSensitivityRatio;
    }

    nuiSize x,y;
    nuiSize range = sqrtf(GetRect().GetWidth() * GetRect().GetHeight());
    x = X-mClickX;
    y = mClickY - Y;

    //nuiSize length = range;
    nuiSize start= mClickValue;
    nuiSize movement = ( x + y ) / sensitivity;

    start += (mRange.GetRange() - mRange.GetPageSize()) * (movement/range);

    mRange.SetValue(start);

    mInteractiveValueChanged = true;
    InteractiveValueChanged();

    // Rotate the contained widget if there is only one:
    /* unused: nuiWidget* pItem = NULL; */

    long count = mpChildren.size();
    if (!count)
      return true;

    return true;
  }

  return false;
}

// Data management:
bool nuiKnob::HandlePageDown(const nuiEvent& rEvent)
{
  mRange.PageIncrement();
  return false;
}

bool nuiKnob::HandlePageUp(const nuiEvent& rEvent)
{
  mRange.PageDecrement();
  return false;
}

nuiRange& nuiKnob::GetRange()
{
  return mRange;
}

bool nuiKnob::DoInvalidate(const nuiEvent& rEvent)
{
  if (mSequenceNeedRefresh)
  {
    delete mpImageSequence;
    mpImageSequence = NULL;

    mpImageSequence = new nuiImageSequence();
    mpImageSequence->SetNbFrames(mSequenceNbFrames);
    mpImageSequence->SetTexturePath(mSequencePath);
    mpImageSequence->SetOrientation(mSequenceOrientation);
    mSequenceNeedRefresh = false;
  }

  Invalidate();
  return false;
}

nuiRect nuiKnob::CalcIdealSize()
{
  if (mpChildren.empty())
  {
    if (!mpImageSequence)
      return nuiRect(0,0,0,0);

    const nuiRect& rect = mpImageSequence->GetIdealRect();
    return rect;
  }
  else
  {
    return nuiSimpleContainer::CalcIdealSize();
  }
}

bool nuiKnob::SetRect(const nuiRect& rRect)
{
  nuiWidget::SetRect(rRect);
  mpImageSequence->SetLayout(rRect);
  return true;
}

bool nuiKnob::Draw(nuiDrawContext* pContext)
{
  if (mpImageSequence)
  {
    mFrameIndex = (int)((mpImageSequence->GetNbFrames()-1) * (mRange.GetValue() - mRange.GetMinimum())) / (mRange.GetMaximum() - mRange.GetMinimum());

    mpImageSequence->SetFrameIndex(mFrameIndex);
    mpImageSequence->Draw(pContext, this);
  }

  return nuiSimpleContainer::Draw(pContext);

}

void nuiKnob::SetDefaultSensitivity(nuiSize DefaultSensitivity)
{
  mDefaultSensitivity = DefaultSensitivity;
}

void nuiKnob::SetSensitivity(nuiSize Sensitivity)
{
  mSensitivity = Sensitivity;
}

// the bigger the ratio is, the slower the knob will turn.
void nuiKnob::SetDefaultFineSensitivityRatio(nuiSize DefaultFineSensitivityRatio)
{
  mDefaultFineSensitivityRatio = DefaultFineSensitivityRatio;
}

void nuiKnob::SetFineSensitivityRatio(nuiSize FineSensitivityRatio)
{
  mFineSensitivityRatio = FineSensitivityRatio;
}

void nuiKnob::SetDefaultFineSensitivityKey(nglKeyCode DefaultFineSensitivityKey)
{
  mDefaultFineSensitivityKey = DefaultFineSensitivityKey;
}

void nuiKnob::SetFineSensitivityKey(nglKeyCode FineSensitivityKey)
{
  mFineSensitivityKey = FineSensitivityKey;
}

<|endoftext|>


<commit_before>/* ************************************************************************
 * Copyright 2018 Advanced Micro Devices, Inc.
 * ************************************************************************ */

#include "rocsparse.h"
#include "handle.h"
#include "utility.h"

#include <hip/hip_runtime.h>

#if defined(__HIP_PLATFORM_HCC__)
#include <rocprim/rocprim.hpp>
#elif defined(__HIP_PLATFORM_NVCC__)
#include <hipcub/hipcub.hpp>
#endif

extern "C" rocsparse_status rocsparse_csrsort_buffer_size(rocsparse_handle handle,
                                                          rocsparse_int m,
                                                          rocsparse_int n,
                                                          rocsparse_int nnz,
                                                          const rocsparse_int* csr_row_ptr,
                                                          const rocsparse_int* csr_col_ind,
                                                          size_t* buffer_size)
{
    // Check for valid handle
    if(handle == nullptr)
    {
        return rocsparse_status_invalid_handle;
    }

    // Logging TODO bench logging
    log_trace(handle, "rocsparse_csrsort_buffer_size",
              m,
              n,
              nnz,
              (const void*&)csr_row_ptr,
              (const void*&)csr_col_ind,
              (const void*&)buffer_size);

    // Check sizes
    if(m < 0)
    {
        return rocsparse_status_invalid_size;
    }
    else if(n < 0)
    {
        return rocsparse_status_invalid_size;
    }
    else if(nnz < 0)
    {
        return rocsparse_status_invalid_size;
    }

    // Check pointer arguments
    if(csr_row_ptr == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }
    else if(csr_col_ind == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }
    else if(buffer_size == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }

    // Quick return if possible
    if(m == 0 || n == 0 || nnz == 0)
    {
        *buffer_size = 0;
        return rocsparse_status_success;
    }

    // Stream
    hipStream_t stream = handle->stream;

    rocsparse_int* null_ptr = nullptr;

// TODO config required for buffer??
#if defined(__HIP_PLATFORM_HCC__)
    using config = rocprim::segmented_radix_sort_config<6, 5, rocprim::kernel_config<64, 1> >;

    rocprim::segmented_radix_sort_pairs<config>(nullptr, *buffer_size, null_ptr, null_ptr, null_ptr, null_ptr, nnz, m, null_ptr, null_ptr, 0, 32, stream);
#elif defined(__HIP_PLATFORM_NVCC__)
    hipcub::DeviceSegmentedRadixSort::SortPairs(nullptr, *buffer_size, null_ptr, null_ptr, null_ptr, null_ptr, nnz, m, null_ptr, null_ptr, 0, 32, stream);
#endif

    return rocsparse_status_success;
}

extern "C" rocsparse_status rocsparse_csrsort(rocsparse_handle handle,
                                              rocsparse_int m,
                                              rocsparse_int n,
                                              rocsparse_int nnz,
                                              const rocsparse_mat_descr descr,
                                              const rocsparse_int* csr_row_ptr,
                                              rocsparse_int* csr_col_ind,
                                              rocsparse_int* perm,
                                              void* temp_buffer)
{
    // Check for valid handle
    if(handle == nullptr)
    {
        return rocsparse_status_invalid_handle;
    }
    else if(descr == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }

    // Logging TODO bench logging
    log_trace(handle, "rocsparse_csrsort_buffer_size",
              m,
              n,
              nnz,
              (const void*&)descr,
              (const void*&)csr_row_ptr,
              (const void*&)csr_col_ind,
              (const void*&)perm,
              (const void*&)temp_buffer);

    // Check sizes
    if(m < 0)
    {
        return rocsparse_status_invalid_size;
    }
    else if(n < 0)
    {
        return rocsparse_status_invalid_size;
    }
    else if(nnz < 0)
    {
        return rocsparse_status_invalid_size;
    }

    // Check pointer arguments
    if(csr_row_ptr == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }
    else if(csr_col_ind == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }
    else if(perm == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }
    else if(temp_buffer == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }

    // Quick return if possible
    if(m == 0 || n == 0 || nnz == 0)
    {
        return rocsparse_status_success;
    }

    // Stream
    hipStream_t stream = handle->stream;

    unsigned int startbit = 0;
    unsigned int endbit = 32 - __builtin_clz(n);
    size_t size;

#if defined(__HIP_PLATFORM_HCC__)
    using config = rocprim::segmented_radix_sort_config<6, 5, rocprim::kernel_config<64, 1> >;

    rocprim::segmented_radix_sort_pairs<config>(nullptr, size, csr_col_ind, csr_col_ind, perm, perm, nnz, m, csr_row_ptr, csr_row_ptr + 1, startbit, endbit, stream);
    rocprim::segmented_radix_sort_pairs<config>(temp_buffer, size, csr_col_ind, csr_col_ind, perm, perm, nnz, m, csr_row_ptr, csr_row_ptr + 1, startbit, endbit, stream);
#elif defined(__HIP_PLATFORM_NVCC__)
    hipcub::DeviceSegmentedRadixSort::SortPairs(nullptr, size, csr_col_ind, csr_col_ind, perm, perm, nnz, m, csr_row_ptr, csr_row_ptr + 1, startbit, endbit, stream);
    hipcub::DeviceSegmentedRadixSort::SortPairs(temp_buffer, size, csr_col_ind, csr_col_ind, perm, perm, nnz, m, csr_row_ptr, csr_row_ptr + 1, startbit, endbit, stream);
#endif

    return rocsparse_status_success;
}
<commit_msg>updated csrsort()<commit_after>/* ************************************************************************
 * Copyright 2018 Advanced Micro Devices, Inc.
 * ************************************************************************ */

#include "rocsparse.h"
#include "handle.h"
#include "utility.h"

#include <hip/hip_runtime.h>

#if defined(__HIP_PLATFORM_HCC__)
#include <rocprim/rocprim.hpp>
#elif defined(__HIP_PLATFORM_NVCC__)
#include <hipcub/hipcub.hpp>
#endif

extern "C" rocsparse_status rocsparse_csrsort_buffer_size(rocsparse_handle handle,
                                                          rocsparse_int m,
                                                          rocsparse_int n,
                                                          rocsparse_int nnz,
                                                          const rocsparse_int* csr_row_ptr,
                                                          const rocsparse_int* csr_col_ind,
                                                          size_t* buffer_size)
{
    // Check for valid handle
    if(handle == nullptr)
    {
        return rocsparse_status_invalid_handle;
    }

    // Logging TODO bench logging
    log_trace(handle, "rocsparse_csrsort_buffer_size",
              m,
              n,
              nnz,
              (const void*&)csr_row_ptr,
              (const void*&)csr_col_ind,
              (const void*&)buffer_size);

    // Check sizes
    if(m < 0)
    {
        return rocsparse_status_invalid_size;
    }
    else if(n < 0)
    {
        return rocsparse_status_invalid_size;
    }
    else if(nnz < 0)
    {
        return rocsparse_status_invalid_size;
    }

    // Check pointer arguments
    if(csr_row_ptr == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }
    else if(csr_col_ind == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }
    else if(buffer_size == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }

    // Quick return if possible
    if(m == 0 || n == 0 || nnz == 0)
    {
        *buffer_size = 0;
        return rocsparse_status_success;
    }

    // Stream
    hipStream_t stream = handle->stream;

    rocsparse_int* null_ptr = nullptr;

// TODO config required for buffer??
#if defined(__HIP_PLATFORM_HCC__)
    using config = rocprim::segmented_radix_sort_config<6, 5, rocprim::kernel_config<64, 1> >;

    rocprim::segmented_radix_sort_pairs<config>(nullptr, *buffer_size, null_ptr, null_ptr, null_ptr, null_ptr, nnz, m, null_ptr, null_ptr, 0, 32, stream);
#elif defined(__HIP_PLATFORM_NVCC__)
    hipcub::DeviceSegmentedRadixSort::SortPairs(nullptr, *buffer_size, null_ptr, null_ptr, null_ptr, null_ptr, nnz, m, null_ptr, null_ptr, 0, 32, stream);
#endif

    // rocPRIM does not support in-place sorting, so we need additional buffer
    // for all temporary arrays

    // columns buffer
    *buffer_size += sizeof(rocsparse_int) * nnz;
    // perm buffer
    *buffer_size += sizeof(rocsparse_int) * nnz;

    return rocsparse_status_success;
}

extern "C" rocsparse_status rocsparse_csrsort(rocsparse_handle handle,
                                              rocsparse_int m,
                                              rocsparse_int n,
                                              rocsparse_int nnz,
                                              const rocsparse_mat_descr descr,
                                              const rocsparse_int* csr_row_ptr,
                                              rocsparse_int* csr_col_ind,
                                              rocsparse_int* perm,
                                              void* temp_buffer)
{
    // Check for valid handle
    if(handle == nullptr)
    {
        return rocsparse_status_invalid_handle;
    }
    else if(descr == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }

    // Logging TODO bench logging
    log_trace(handle, "rocsparse_csrsort_buffer_size",
              m,
              n,
              nnz,
              (const void*&)descr,
              (const void*&)csr_row_ptr,
              (const void*&)csr_col_ind,
              (const void*&)perm,
              (const void*&)temp_buffer);

    // Check sizes
    if(m < 0)
    {
        return rocsparse_status_invalid_size;
    }
    else if(n < 0)
    {
        return rocsparse_status_invalid_size;
    }
    else if(nnz < 0)
    {
        return rocsparse_status_invalid_size;
    }

    // Check pointer arguments
    if(csr_row_ptr == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }
    else if(csr_col_ind == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }
    else if(perm == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }
    else if(temp_buffer == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }

    // Quick return if possible
    if(m == 0 || n == 0 || nnz == 0)
    {
        return rocsparse_status_success;
    }

    // Stream
    hipStream_t stream = handle->stream;

    unsigned int startbit = 0;
    unsigned int endbit = rocsparse_clz(n);
    size_t size;

#if defined(__HIP_PLATFORM_HCC__)
    rocprim::segmented_radix_sort_pairs(nullptr, size, csr_col_ind, csr_col_ind, perm, perm, nnz, m, csr_row_ptr, csr_row_ptr + 1, startbit, endbit, stream);

    // Temporary buffer entry points
    char* ptr = reinterpret_cast<char*>(temp_buffer);
    ptr += size;

    // columns buffer
    rocsparse_int* tmp_cols = reinterpret_cast<rocsparse_int*>(ptr);
    ptr += sizeof(rocsparse_int) * nnz;

    // perm buffer
    rocsparse_int* tmp_perm = reinterpret_cast<rocsparse_int*>(ptr);

    // Sort by columns and obtain permutation vector

    // Determine blocksize and items per thread depending on average nnz per row
    rocsparse_int avg_row_nnz = nnz / m;

    if(avg_row_nnz < 64)
    {
        using config = rocprim::segmented_radix_sort_config<6, 5, rocprim::kernel_config<64, 1> >;
        rocprim::segmented_radix_sort_pairs<config>(temp_buffer, size, csr_col_ind, tmp_cols, perm, tmp_perm, nnz, m, csr_row_ptr, csr_row_ptr + 1, startbit, endbit, stream);
    }
    else if(avg_row_nnz < 128)
    {
        using config = rocprim::segmented_radix_sort_config<6, 5, rocprim::kernel_config<64, 2> >;
        rocprim::segmented_radix_sort_pairs<config>(temp_buffer, size, csr_col_ind, tmp_cols, perm, tmp_perm, nnz, m, csr_row_ptr, csr_row_ptr + 1, startbit, endbit, stream);
    }
    else if(avg_row_nnz < 256)
    {
        using config = rocprim::segmented_radix_sort_config<6, 5, rocprim::kernel_config<64, 4> >;
        rocprim::segmented_radix_sort_pairs<config>(temp_buffer, size, csr_col_ind, tmp_cols, perm, tmp_perm, nnz, m, csr_row_ptr, csr_row_ptr + 1, startbit, endbit, stream);
    }
    else
    {
        rocprim::segmented_radix_sort_pairs(temp_buffer, size, csr_col_ind, tmp_cols, perm, tmp_perm, nnz, m, csr_row_ptr, csr_row_ptr + 1, startbit, endbit, stream);
    }
#elif defined(__HIP_PLATFORM_NVCC__)
    hipcub::DeviceSegmentedRadixSort::SortPairs(nullptr, size, csr_col_ind, csr_col_ind, perm, perm, nnz, m, csr_row_ptr, csr_row_ptr + 1, startbit, endbit, stream);

    // Temporary buffer entry points
    char* ptr = reinterpret_cast<char*>(temp_buffer);
    ptr += size;

    // columns buffer
    rocsparse_int* tmp_cols = reinterpret_cast<rocsparse_int*>(ptr);
    ptr += sizeof(rocsparse_int) * nnz;

    // perm buffer
    rocsparse_int* tmp_perm = reinterpret_cast<rocsparse_int*>(ptr);

    // Sort by columns and obtain permutation vector
    hipcub::DeviceSegmentedRadixSort::SortPairs(temp_buffer, size, csr_col_ind, tmp_cols, perm, tmp_perm, nnz, m, csr_row_ptr, csr_row_ptr + 1, startbit, endbit, stream);
#endif

    // Extract results from buffer
    hipMemcpy(csr_col_ind, tmp_cols, sizeof(rocsparse_int) * nnz, hipMemcpyDeviceToDevice);
    hipMemcpy(perm, tmp_perm, sizeof(rocsparse_int) * nnz, hipMemcpyDeviceToDevice);

    return rocsparse_status_success;
}
<|endoftext|>


<commit_before>/******************************************************************************

Copyright (c) Dmitri Dolzhenko

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

*******************************************************************************/

// #include "test_basics.hpp"

//------------------------------------------------------------------------------

// include local:
#include "limo/test_main.hpp"

// include std:

// forward declarations:

//------------------------------------------------------------------------------

// + all macroses
// + __file__ ___line__
// + setup/teardown  anyway
// - print calculated values (if possible)
// + statistics
// + includeonly
// - context:     CONTEXT(sort, {selection_sort, naive_sort})
// - select tests to run test_context__.run("search.*")
// - separate printers and config
// - assert marcroses

// 0.3
// - base test example
// - test example with 2 algoritms

// 0.5:

int my_sqare(int x)
{
    if (x == 3)
        return 3;
    return x*x;
}

LTEST(my_sqare) {

    using namespace limo;

    EXPECT_TRUE(2==2);
    EXPECT_FALSE(2==3);

    EXPECT_TRUE(2==2);
    EXPECT_LT(2, 2);

    EXPECT_TRUE(in({1, 2} , 42));
    EXPECT_TRUE(in({1, 2} , 2));

    EXPECT_EQ(1, 1);

    // auto my_sqare = [](int x) { return x * x; };

    LTEST(degenarated) {
        EXPECT_EQ(0, my_sqare(0));
    };
    LTEST(trivial) {
        EXPECT_EQ(1, my_sqare(1));
    };

    LTEST(even) {
        LTEST(positive) {
            EXPECT_EQ(4, my_sqare(2));
            EXPECT_EQ(16, my_sqare(4));
        };
        LTEST(negative) {
            EXPECT_EQ(4, my_sqare(-2));
            EXPECT_EQ(16, my_sqare(-4));
        };
    };

    LTEST(odd) {
        LTEST(positive) {
            EXPECT_EQ(9, my_sqare(3));
            EXPECT_EQ(25, my_sqare(5));
        };
        LTEST(negative) {
            EXPECT_EQ(9, my_sqare(-3));
            EXPECT_EQ(25, my_sqare(-5));
        };
    };
};<commit_msg>test lambda mutabelnost<commit_after>/******************************************************************************

Copyright (c) Dmitri Dolzhenko

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

*******************************************************************************/

// #include "test_basics.hpp"

//------------------------------------------------------------------------------

// include local:
#include "limo/test_main.hpp"

// include std:

// forward declarations:

//------------------------------------------------------------------------------

// + all macroses
// + __file__ ___line__
// + setup/teardown  anyway
// - print calculated values (if possible)
// + statistics
// + includeonly
// - context:     CONTEXT(sort, {selection_sort, naive_sort})
// - select tests to run test_context__.run("search.*")
// - separate printers and config
// - assert marcroses

// 0.3
// - base test example
// - test example with 2 algoritms

// 0.5:

int my_sqare(int x)
{
    if (x == 3)
        return 3;
    return x*x;
}

LTEST(lambda_mutabelnost) {
    using namespace std;

    int x = 42;

    auto foo = [x]() mutable {
        x = 13;
    };

    EXPECT_EQ(x, 42);

    x = 128;
    EXPECT_EQ(x, 128);

    foo();
    EXPECT_EQ(x, 128);
};

LTEST(my_sqare) {

    using namespace limo;

    EXPECT_TRUE(2==2);
    EXPECT_FALSE(2==3);

    EXPECT_TRUE(2==2);

    EXPECT_TRUE(in({1, 2} , 2));

    EXPECT_EQ(1, 1);

    // auto my_sqare = [](int x) { return x * x; };

    LTEST(degenarated) {
        EXPECT_EQ(0, my_sqare(0));
    };
    LTEST(trivial) {
        EXPECT_EQ(1, my_sqare(1));
    };

    LTEST(even) {
        LTEST(positive) {
            EXPECT_EQ(4, my_sqare(2));
            EXPECT_EQ(16, my_sqare(4));
        };
        LTEST(negative) {
            EXPECT_EQ(4, my_sqare(-2));
            EXPECT_EQ(16, my_sqare(-4));
        };
    };

    LTEST(odd) {
        LTEST(positive) {
            // EXPECT_EQ(9, my_sqare(3));
            EXPECT_EQ(25, my_sqare(5));
        };
        LTEST(negative) {
            EXPECT_EQ(9, my_sqare(-3));
            EXPECT_EQ(25, my_sqare(-5));
        };
    };
};<|endoftext|>


<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include <mitkSliceNavigationController.h>
#include <mitkBaseRenderer.h>
#include <mitkRenderWindow.h>
#include <mitkSlicedGeometry3D.h>
#include <mitkPlaneGeometry.h>
#include <mitkOperation.h>
#include <mitkOperationActor.h>
#include <mitkPositionEvent.h>
#include <mitkInteractionConst.h>
#include <mitkAction.h>
#include <mitkGlobalInteraction.h>
#include <mitkEventMapper.h>
#include <mitkFocusManager.h>
#include <mitkOpenGLRenderer.h>
#include <mitkRenderingManager.h>

#include <mitkInteractionConst.h>
#include <mitkPointOperation.h>

#include <itkCommand.h>

namespace mitk {

//##ModelId=3E189B1D008D
SliceNavigationController::SliceNavigationController(const char * type)
: BaseController(type), m_InputWorldGeometry(NULL), m_CreatedWorldGeometry(NULL), m_ViewDirection(Transversal), m_BlockUpdate(false)
{
  itk::SimpleMemberCommand<SliceNavigationController>::Pointer sliceStepperChangedCommand, timeStepperChangedCommand;
  sliceStepperChangedCommand = itk::SimpleMemberCommand<SliceNavigationController>::New();
  timeStepperChangedCommand = itk::SimpleMemberCommand<SliceNavigationController>::New();
  sliceStepperChangedCommand->SetCallbackFunction(this, &SliceNavigationController::SendSlice);
  timeStepperChangedCommand->SetCallbackFunction(this,  &SliceNavigationController::SendTime);

  m_Slice->AddObserver(itk::ModifiedEvent(), sliceStepperChangedCommand);
  m_Time->AddObserver(itk::ModifiedEvent(),  timeStepperChangedCommand);
  ConnectGeometryEvents(this);
}

//##ModelId=3E189B1D00BF
SliceNavigationController::~SliceNavigationController()
{

}

void SliceNavigationController::SetInputWorldGeometry(const Geometry3D* geometry)
{
  if(geometry != NULL)
  {
    if(const_cast<BoundingBox*>(geometry->GetBoundingBox())->GetDiagonalLength2()<eps)
    {
      itkWarningMacro("setting an empty bounding-box");
      geometry = NULL;
    }
  }
  if(m_InputWorldGeometry != geometry)
  {
    m_InputWorldGeometry = geometry;
    Modified();
  }
}

void SliceNavigationController::Update()
{
  if(m_BlockUpdate)
    return;

  if(m_ViewDirection == Transversal)
  {
    Update(Transversal, false, false, true);
  }
  else
  {
    Update(m_ViewDirection);
  } }
void SliceNavigationController::Update(SliceNavigationController::ViewDirection viewDirection, bool top, bool frontside, bool rotated)
{
  if(m_InputWorldGeometry.IsNull())
    return;
  if(m_BlockUpdate)
    return;
  m_BlockUpdate = true;

  if(m_LastUpdateTime < m_InputWorldGeometry->GetMTime())
  {
    Modified();
  }
  SetViewDirection(viewDirection);
  SetTop(top);
  SetFrontSide(frontside);
  SetRotated(rotated);

  if(m_LastUpdateTime < GetMTime())
  {
    m_LastUpdateTime = GetMTime();

    // initialize the viewplane
    PlaneGeometry::Pointer planegeometry = PlaneGeometry::New();

    SlicedGeometry3D::Pointer slicedWorldGeometry = NULL;

    m_CreatedWorldGeometry = NULL;
    const TimeSlicedGeometry* worldTimeSlicedGeometry = dynamic_cast<const TimeSlicedGeometry*>(m_InputWorldGeometry.GetPointer());
    switch(viewDirection)
    {
    case Original:
      if(worldTimeSlicedGeometry != NULL)
      {
        m_CreatedWorldGeometry =
          static_cast<TimeSlicedGeometry*>(m_InputWorldGeometry->Clone().GetPointer());
        worldTimeSlicedGeometry = m_CreatedWorldGeometry.GetPointer();
        slicedWorldGeometry = dynamic_cast<SlicedGeometry3D*>(m_CreatedWorldGeometry->GetGeometry3D(0));
        if(slicedWorldGeometry.IsNotNull())
        {
          break;
        }
      }
      else
      {
        const SlicedGeometry3D* worldSlicedGeometry = dynamic_cast<const SlicedGeometry3D*>(m_InputWorldGeometry.GetPointer());
        if(worldSlicedGeometry != NULL)
        {
          slicedWorldGeometry = static_cast<SlicedGeometry3D*>(m_InputWorldGeometry->Clone().GetPointer());
          break;
        }
      }
      //else: use Transversal: no "break" here!!
    case Transversal:
      slicedWorldGeometry=SlicedGeometry3D::New();
      slicedWorldGeometry->InitializePlanes(m_InputWorldGeometry, PlaneGeometry::Transversal, top, frontside, rotated);
      break;
    case Frontal:
      slicedWorldGeometry=SlicedGeometry3D::New();
      slicedWorldGeometry->InitializePlanes(m_InputWorldGeometry, PlaneGeometry::Frontal, top, frontside, rotated);
      break;
    case Sagittal:
      slicedWorldGeometry=SlicedGeometry3D::New();
      slicedWorldGeometry->InitializePlanes(m_InputWorldGeometry, PlaneGeometry::Sagittal, top, frontside, rotated);
      break;
    default:
      itkExceptionMacro("unknown ViewDirection");
    }

    m_Slice->SetPos(0);

    m_Slice->SetSteps((int)slicedWorldGeometry->GetSlices());

  if(m_CreatedWorldGeometry.IsNull())
  {
    // initialize TimeSlicedGeometry
    m_CreatedWorldGeometry = TimeSlicedGeometry::New();
  }
  if(worldTimeSlicedGeometry==NULL)
  {
    m_CreatedWorldGeometry->InitializeEvenlyTimed(slicedWorldGeometry, 1);
    m_Time->SetSteps(0);
    m_Time->SetPos(0);
  }
  else
  {
    m_BlockUpdate = true;
    m_Time->SetSteps(worldTimeSlicedGeometry->GetTimeSteps());
    m_Time->SetPos(0);
    m_BlockUpdate = false;

    slicedWorldGeometry->SetTimeBounds(worldTimeSlicedGeometry->GetGeometry3D(0)->GetTimeBounds());
    //@todo implement for non-evenly-timed geometry!
    m_CreatedWorldGeometry->InitializeEvenlyTimed(slicedWorldGeometry, worldTimeSlicedGeometry->GetTimeSteps());
  }
}

  //unblock update; we may do this now, because if m_BlockUpdate was already true before this method was entered,
  //then we will never come here.
  m_BlockUpdate = false;

  //Send the geometry. Do this even if nothing was changed, because maybe Update() was only called to
  //re-send the old geometry and time/slice data.
  this->SendCreatedWorldGeometry();
  this->SendSlice();
  this->SendTime();
}

void SliceNavigationController::SendCreatedWorldGeometry()
{
  //Send the geometry. Do this even if nothing was changed, because maybe Update() was only called to
  //re-send the old geometry.
  if(!m_BlockUpdate)
    InvokeEvent(GeometrySendEvent(m_CreatedWorldGeometry, 0));
}

void SliceNavigationController::SendCreatedWorldGeometryUpdate()
{
  if(!m_BlockUpdate)
    InvokeEvent(GeometryUpdateEvent(m_CreatedWorldGeometry, m_Slice->GetPos()));
}

//##ModelId=3DD524D7038C
void SliceNavigationController::SendSlice()
{
  if(!m_BlockUpdate)
  {
    if(m_CreatedWorldGeometry.IsNotNull())
    {
      InvokeEvent(GeometrySliceEvent(m_CreatedWorldGeometry, m_Slice->GetPos()));

      // Request rendering update for all views
      RenderingManager::GetInstance()->RequestUpdateAll();
    }
  }
}

void SliceNavigationController::SendTime()
{
  if(!m_BlockUpdate)
  {
    if(m_CreatedWorldGeometry.IsNotNull())
    {
      InvokeEvent(GeometryTimeEvent(m_CreatedWorldGeometry, m_Time->GetPos()));

      // Request rendering update for all views
      RenderingManager::GetInstance()->RequestUpdateAll();
    }
  }
}

void SliceNavigationController::SetGeometry(const itk::EventObject & geometrySendEvent)
{
}

void SliceNavigationController::SetGeometryTime(const itk::EventObject & geometryTimeEvent)
{
  const SliceNavigationController::GeometryTimeEvent * timeEvent =
    dynamic_cast<const SliceNavigationController::GeometryTimeEvent *>(&geometryTimeEvent);
  assert(timeEvent!=NULL);

  TimeSlicedGeometry* timeSlicedGeometry = timeEvent->GetTimeSlicedGeometry();
  assert(timeSlicedGeometry!=NULL);

  if(m_CreatedWorldGeometry.IsNotNull())
  {
    int timeStep = (int) timeEvent->GetPos();
    ScalarType timeInMS;
    timeInMS = timeSlicedGeometry->TimeStepToMS(timeStep);
    timeStep = m_CreatedWorldGeometry->MSToTimeStep(timeInMS);
    GetTime()->SetPos(timeStep);
  }
}

void SliceNavigationController::SetGeometrySlice(const itk::EventObject & geometrySliceEvent)
{
  const SliceNavigationController::GeometrySliceEvent* sliceEvent =
    dynamic_cast<const SliceNavigationController::GeometrySliceEvent *>(&geometrySliceEvent);
  assert(sliceEvent!=NULL);

  GetSlice()->SetPos(sliceEvent->GetPos());
}

void SliceNavigationController::ExecuteOperation(Operation* operation)
{
  // switch on type
  // - select best slice for a given point
  // - rotate created world geometry according to Operation->SomeInfo()
  if (!operation) return;

  switch ( operation->GetOperationType() )
  {
    case OpMOVE: // should be a point operation
    {
      // select a slice
      PointOperation* po = dynamic_cast<PointOperation*>(operation);
      if (!po) return;

      Point3D point = po->GetPoint();
      //@todo add time to PositionEvent and use here!!
      SlicedGeometry3D* slicedWorldGeometry = dynamic_cast<SlicedGeometry3D*>( m_CreatedWorldGeometry->GetGeometry3D(0) );
      if ( slicedWorldGeometry )
      {
        int best_slice = -1;
        double best_distance = itk::NumericTraits<double>::max();

        int s, slices;
        slices = slicedWorldGeometry->GetSlices();
        if(slicedWorldGeometry->GetEvenlySpaced())
        {
          Point3D pointInUnits;
          slicedWorldGeometry->WorldToIndex(point, pointInUnits);
          best_slice = (int)(pointInUnits[2]+0.5);
        }
        else
        {
          Point3D projected_point;
          for( s=0; s < slices; ++s )
          {
            slicedWorldGeometry->GetGeometry2D(s)->Project(point, projected_point);
            Vector3D dist = projected_point - point;
            ScalarType curDist = dist.GetSquaredNorm();
            if(curDist < best_distance)
            {
              best_distance = curDist;
              best_slice    = s;
            }
          }
        }
        if(best_slice >= 0)
          GetSlice()->SetPos(best_slice);
      }

      break;
    }
    default:
    {
      // do nothing
      break;
    }
  }
}

/// Relict from the old times, when automous descisions were accepted behaviour.
/// Remains in here, because some RenderWindows do exist outide of StdMultiWidgets.
bool SliceNavigationController::ExecuteAction( Action* action, StateEvent const* stateEvent)
{
  bool ok = false;

  const PositionEvent* posEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
  if(posEvent!=NULL)
  {
    if(m_CreatedWorldGeometry.IsNull())
      return true;
    switch (action->GetActionId())
    {
    case AcMOVE:
      {
        BaseRenderer* baseRenderer = posEvent->GetSender();
        if (!baseRenderer)
        {
          baseRenderer = const_cast<BaseRenderer *>( GlobalInteraction::GetInstance()->GetFocus() );
        }
        if (baseRenderer)
          if (baseRenderer->GetMapperID() == 1)
          {
            PointOperation po( OpMOVE, posEvent->GetWorldPosition() );

            ExecuteOperation( &po ); // select best slice
          }
          ok = true;
          break;
      }
    default:
      ok = true;
      break;
    }
    return ok;
  }

  const DisplayPositionEvent* displPosEvent = dynamic_cast<const DisplayPositionEvent *>(stateEvent->GetEvent());
  if(displPosEvent!=NULL)
  {
    return true;
  }

  return false;
}

} // namespace

<commit_msg>FIX: useless self-informing connection<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include <mitkSliceNavigationController.h>
#include <mitkBaseRenderer.h>
#include <mitkRenderWindow.h>
#include <mitkSlicedGeometry3D.h>
#include <mitkPlaneGeometry.h>
#include <mitkOperation.h>
#include <mitkOperationActor.h>
#include <mitkPositionEvent.h>
#include <mitkInteractionConst.h>
#include <mitkAction.h>
#include <mitkGlobalInteraction.h>
#include <mitkEventMapper.h>
#include <mitkFocusManager.h>
#include <mitkOpenGLRenderer.h>
#include <mitkRenderingManager.h>

#include <mitkInteractionConst.h>
#include <mitkPointOperation.h>

#include <itkCommand.h>

namespace mitk {

//##ModelId=3E189B1D008D
SliceNavigationController::SliceNavigationController(const char * type)
: BaseController(type), m_InputWorldGeometry(NULL), m_CreatedWorldGeometry(NULL), m_ViewDirection(Transversal), m_BlockUpdate(false)
{
  itk::SimpleMemberCommand<SliceNavigationController>::Pointer sliceStepperChangedCommand, timeStepperChangedCommand;
  sliceStepperChangedCommand = itk::SimpleMemberCommand<SliceNavigationController>::New();
  timeStepperChangedCommand = itk::SimpleMemberCommand<SliceNavigationController>::New();
  sliceStepperChangedCommand->SetCallbackFunction(this, &SliceNavigationController::SendSlice);
  timeStepperChangedCommand->SetCallbackFunction(this,  &SliceNavigationController::SendTime);

  m_Slice->AddObserver(itk::ModifiedEvent(), sliceStepperChangedCommand);
  m_Time->AddObserver(itk::ModifiedEvent(),  timeStepperChangedCommand);
}

//##ModelId=3E189B1D00BF
SliceNavigationController::~SliceNavigationController()
{

}

void SliceNavigationController::SetInputWorldGeometry(const Geometry3D* geometry)
{
  if(geometry != NULL)
  {
    if(const_cast<BoundingBox*>(geometry->GetBoundingBox())->GetDiagonalLength2()<eps)
    {
      itkWarningMacro("setting an empty bounding-box");
      geometry = NULL;
    }
  }
  if(m_InputWorldGeometry != geometry)
  {
    m_InputWorldGeometry = geometry;
    Modified();
  }
}

void SliceNavigationController::Update()
{
  if(m_BlockUpdate)
    return;

  if(m_ViewDirection == Transversal)
  {
    Update(Transversal, false, false, true);
  }
  else
  {
    Update(m_ViewDirection);
  } }
void SliceNavigationController::Update(SliceNavigationController::ViewDirection viewDirection, bool top, bool frontside, bool rotated)
{
  if(m_InputWorldGeometry.IsNull())
    return;
  if(m_BlockUpdate)
    return;
  m_BlockUpdate = true;

  if(m_LastUpdateTime < m_InputWorldGeometry->GetMTime())
  {
    Modified();
  }
  SetViewDirection(viewDirection);
  SetTop(top);
  SetFrontSide(frontside);
  SetRotated(rotated);

  if(m_LastUpdateTime < GetMTime())
  {
    m_LastUpdateTime = GetMTime();

    // initialize the viewplane
    PlaneGeometry::Pointer planegeometry = PlaneGeometry::New();

    SlicedGeometry3D::Pointer slicedWorldGeometry = NULL;

    m_CreatedWorldGeometry = NULL;
    const TimeSlicedGeometry* worldTimeSlicedGeometry = dynamic_cast<const TimeSlicedGeometry*>(m_InputWorldGeometry.GetPointer());
    switch(viewDirection)
    {
    case Original:
      if(worldTimeSlicedGeometry != NULL)
      {
        m_CreatedWorldGeometry =
          static_cast<TimeSlicedGeometry*>(m_InputWorldGeometry->Clone().GetPointer());
        worldTimeSlicedGeometry = m_CreatedWorldGeometry.GetPointer();
        slicedWorldGeometry = dynamic_cast<SlicedGeometry3D*>(m_CreatedWorldGeometry->GetGeometry3D(0));
        if(slicedWorldGeometry.IsNotNull())
        {
          break;
        }
      }
      else
      {
        const SlicedGeometry3D* worldSlicedGeometry = dynamic_cast<const SlicedGeometry3D*>(m_InputWorldGeometry.GetPointer());
        if(worldSlicedGeometry != NULL)
        {
          slicedWorldGeometry = static_cast<SlicedGeometry3D*>(m_InputWorldGeometry->Clone().GetPointer());
          break;
        }
      }
      //else: use Transversal: no "break" here!!
    case Transversal:
      slicedWorldGeometry=SlicedGeometry3D::New();
      slicedWorldGeometry->InitializePlanes(m_InputWorldGeometry, PlaneGeometry::Transversal, top, frontside, rotated);
      break;
    case Frontal:
      slicedWorldGeometry=SlicedGeometry3D::New();
      slicedWorldGeometry->InitializePlanes(m_InputWorldGeometry, PlaneGeometry::Frontal, top, frontside, rotated);
      break;
    case Sagittal:
      slicedWorldGeometry=SlicedGeometry3D::New();
      slicedWorldGeometry->InitializePlanes(m_InputWorldGeometry, PlaneGeometry::Sagittal, top, frontside, rotated);
      break;
    default:
      itkExceptionMacro("unknown ViewDirection");
    }

    m_Slice->SetPos(0);

    m_Slice->SetSteps((int)slicedWorldGeometry->GetSlices());

  if(m_CreatedWorldGeometry.IsNull())
  {
    // initialize TimeSlicedGeometry
    m_CreatedWorldGeometry = TimeSlicedGeometry::New();
  }
  if(worldTimeSlicedGeometry==NULL)
  {
    m_CreatedWorldGeometry->InitializeEvenlyTimed(slicedWorldGeometry, 1);
    m_Time->SetSteps(0);
    m_Time->SetPos(0);
  }
  else
  {
    m_BlockUpdate = true;
    m_Time->SetSteps(worldTimeSlicedGeometry->GetTimeSteps());
    m_Time->SetPos(0);
    m_BlockUpdate = false;

    slicedWorldGeometry->SetTimeBounds(worldTimeSlicedGeometry->GetGeometry3D(0)->GetTimeBounds());
    //@todo implement for non-evenly-timed geometry!
    m_CreatedWorldGeometry->InitializeEvenlyTimed(slicedWorldGeometry, worldTimeSlicedGeometry->GetTimeSteps());
  }
}

  //unblock update; we may do this now, because if m_BlockUpdate was already true before this method was entered,
  //then we will never come here.
  m_BlockUpdate = false;

  //Send the geometry. Do this even if nothing was changed, because maybe Update() was only called to
  //re-send the old geometry and time/slice data.
  this->SendCreatedWorldGeometry();
  this->SendSlice();
  this->SendTime();
}

void SliceNavigationController::SendCreatedWorldGeometry()
{
  //Send the geometry. Do this even if nothing was changed, because maybe Update() was only called to
  //re-send the old geometry.
  if(!m_BlockUpdate)
    InvokeEvent(GeometrySendEvent(m_CreatedWorldGeometry, 0));
}

void SliceNavigationController::SendCreatedWorldGeometryUpdate()
{
  if(!m_BlockUpdate)
    InvokeEvent(GeometryUpdateEvent(m_CreatedWorldGeometry, m_Slice->GetPos()));
}

//##ModelId=3DD524D7038C
void SliceNavigationController::SendSlice()
{
  if(!m_BlockUpdate)
  {
    if(m_CreatedWorldGeometry.IsNotNull())
    {
      InvokeEvent(GeometrySliceEvent(m_CreatedWorldGeometry, m_Slice->GetPos()));

      // Request rendering update for all views
      RenderingManager::GetInstance()->RequestUpdateAll();
    }
  }
}

void SliceNavigationController::SendTime()
{
  if(!m_BlockUpdate)
  {
    if(m_CreatedWorldGeometry.IsNotNull())
    {
      InvokeEvent(GeometryTimeEvent(m_CreatedWorldGeometry, m_Time->GetPos()));

      // Request rendering update for all views
      RenderingManager::GetInstance()->RequestUpdateAll();
    }
  }
}

void SliceNavigationController::SetGeometry(const itk::EventObject & geometrySendEvent)
{
}

void SliceNavigationController::SetGeometryTime(const itk::EventObject & geometryTimeEvent)
{
  const SliceNavigationController::GeometryTimeEvent * timeEvent =
    dynamic_cast<const SliceNavigationController::GeometryTimeEvent *>(&geometryTimeEvent);
  assert(timeEvent!=NULL);

  TimeSlicedGeometry* timeSlicedGeometry = timeEvent->GetTimeSlicedGeometry();
  assert(timeSlicedGeometry!=NULL);

  if(m_CreatedWorldGeometry.IsNotNull())
  {
    int timeStep = (int) timeEvent->GetPos();
    ScalarType timeInMS;
    timeInMS = timeSlicedGeometry->TimeStepToMS(timeStep);
    timeStep = m_CreatedWorldGeometry->MSToTimeStep(timeInMS);
    GetTime()->SetPos(timeStep);
  }
}

void SliceNavigationController::SetGeometrySlice(const itk::EventObject & geometrySliceEvent)
{
  const SliceNavigationController::GeometrySliceEvent* sliceEvent =
    dynamic_cast<const SliceNavigationController::GeometrySliceEvent *>(&geometrySliceEvent);
  assert(sliceEvent!=NULL);

  GetSlice()->SetPos(sliceEvent->GetPos());
}

void SliceNavigationController::ExecuteOperation(Operation* operation)
{
  // switch on type
  // - select best slice for a given point
  // - rotate created world geometry according to Operation->SomeInfo()
  if (!operation) return;

  switch ( operation->GetOperationType() )
  {
    case OpMOVE: // should be a point operation
    {
      // select a slice
      PointOperation* po = dynamic_cast<PointOperation*>(operation);
      if (!po) return;

      Point3D point = po->GetPoint();
      //@todo add time to PositionEvent and use here!!
      SlicedGeometry3D* slicedWorldGeometry = dynamic_cast<SlicedGeometry3D*>( m_CreatedWorldGeometry->GetGeometry3D(0) );
      if ( slicedWorldGeometry )
      {
        int best_slice = -1;
        double best_distance = itk::NumericTraits<double>::max();

        int s, slices;
        slices = slicedWorldGeometry->GetSlices();
        if(slicedWorldGeometry->GetEvenlySpaced())
        {
          Point3D pointInUnits;
          slicedWorldGeometry->WorldToIndex(point, pointInUnits);
          best_slice = (int)(pointInUnits[2]+0.5);
        }
        else
        {
          Point3D projected_point;
          for( s=0; s < slices; ++s )
          {
            slicedWorldGeometry->GetGeometry2D(s)->Project(point, projected_point);
            Vector3D dist = projected_point - point;
            ScalarType curDist = dist.GetSquaredNorm();
            if(curDist < best_distance)
            {
              best_distance = curDist;
              best_slice    = s;
            }
          }
        }
        if(best_slice >= 0)
          GetSlice()->SetPos(best_slice);
      }

      break;
    }
    default:
    {
      // do nothing
      break;
    }
  }
}

/// Relict from the old times, when automous descisions were accepted behaviour.
/// Remains in here, because some RenderWindows do exist outide of StdMultiWidgets.
bool SliceNavigationController::ExecuteAction( Action* action, StateEvent const* stateEvent)
{
  bool ok = false;

  const PositionEvent* posEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
  if(posEvent!=NULL)
  {
    if(m_CreatedWorldGeometry.IsNull())
      return true;
    switch (action->GetActionId())
    {
    case AcMOVE:
      {
        BaseRenderer* baseRenderer = posEvent->GetSender();
        if (!baseRenderer)
        {
          baseRenderer = const_cast<BaseRenderer *>( GlobalInteraction::GetInstance()->GetFocus() );
        }
        if (baseRenderer)
          if (baseRenderer->GetMapperID() == 1)
          {
            PointOperation po( OpMOVE, posEvent->GetWorldPosition() );

            ExecuteOperation( &po ); // select best slice
          }
          ok = true;
          break;
      }
    default:
      ok = true;
      break;
    }
    return ok;
  }

  const DisplayPositionEvent* displPosEvent = dynamic_cast<const DisplayPositionEvent *>(stateEvent->GetEvent());
  if(displPosEvent!=NULL)
  {
    return true;
  }

  return false;
}

} // namespace

<|endoftext|>


<commit_before>/** @file
 *
 * @ingroup dspGeneratorLib
 *
 * @brief GeneratorLib: Generate a basic, cycling waveform using a wavetable.
 *
 * @details Wavetable is currently limited to using an internal buffer for managing its waveshape.  Shape options include sine, triangle and sawtooth.
 *
 * @see TTBuffer, TTSampleMatrix, TTMatrix, TTAudioSignal
 *
 * @authors Tim Place, Nathan Wolek
 *
 * @copyright Copyright © 2003-2013 by Timothy Place & Nathan Wolek @n
 * This code is licensed under the terms of the "New BSD License" @n
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTWavetable.h"

#define thisTTClass			TTWavetable
#define thisTTClassName		"wavetable"
#define thisTTClassTags		"audio, generator, oscillator, buffer"

TT_AUDIO_CONSTRUCTOR,
	mIndex(0.0),
	mIndexDelta(0.0),
	mBuffer(NULL),
	mWavetable(NULL)
{
	TTUInt16	initialMaxNumChannels = arguments;

	addAttributeWithSetter(Frequency,		kTypeFloat64);
	addAttributeWithSetter(Mode,			kTypeSymbol);
	addAttributeWithSetter(Gain,			kTypeFloat64);
	addAttributeWithSetter(Interpolation,	kTypeSymbol);
	addAttributeWithSetter(Size,			kTypeUInt32);

	addUpdates(SampleRate);

	TTObjectBaseInstantiate("buffer", (TTObjectBasePtr*)&mBuffer, kTTValNONE);
	if (!mBuffer)
		throw TTException("Could not create internal buffer object");
	mBuffer->setNumChannels(TTUInt32(1));
	mBuffer->checkOutMatrix(mWavetable);

	// Set Defaults...
	setAttributeValue("maxNumChannels",	initialMaxNumChannels);
	setAttributeValue("size", 8192);
	setAttributeValue("mode", kTTSym_sine);
	setAttributeValue("frequency", 440.0);
	setAttributeValue("gain", 0.0);			// 0 dB
	setAttributeValue("interpolation", "linear");
}

TTWavetable::~TTWavetable()
{
	TTObjectBaseRelease((TTObjectBase**)&mBuffer);
}

TTErr TTWavetable::updateSampleRate(const TTValue&, TTValue&)
{
	setAttributeValue("frequency", mFrequency);
	return kTTErrNone;
}

TTErr TTWavetable::setFrequency(const TTValue& newValue)
{
	mFrequency = TTClip<TTFloat64>(newValue, 0.0, sr/2.0);
	mIndexDelta = mFrequency * mSize * srInv;
	return kTTErrNone;
}

TTErr TTWavetable::setMode(const TTValue& newValue)
{
	mMode = newValue;	// TODO: should be newValue[0]

	if (mMode != "externalBuffer")
		return mBuffer->fill(newValue, kTTValNONE);
	else {
		// TODO: implement the ability to use an externally defined buffer
		return kTTErrInvalidValue;
	}
}

TTErr TTWavetable::setInterpolation(const TTValue& newValue)
{
	mMode = newValue;
	if (mMode == "linear")
		setProcessMethod(processWithLinearInterpolation);
	else if (mMode == "lfo")
		setProcessMethod(processAsLFO);
	else
		setProcessMethod(processWithNoInterpolation);
	return kTTErrNone;
}

TTErr TTWavetable::setGain(const TTValue& newValue)
{
	mGain = newValue;
	mLinearGain = TTDecibelsToLinearGain(mGain);
	return kTTErrNone;
}

TTErr TTWavetable::setSize(const TTValue& newSize)
{
	mSize = newSize;
	mBuffer->setLengthInSamples(mSize);
	return setFrequency(mFrequency); // touch the frequency so that the step size is updated
}

// LFO mode only updates values once per vector in order to be as fast as possible
// LFO mode cannot be modulated
TTErr TTWavetable::processAsLFO(TTAudioSignalArrayPtr, TTAudioSignalArrayPtr outputs)
{
	TTAudioSignal&		out = outputs->getSignal(0);
	TTSampleValue		tempSample;
	TTUInt16			vs = out.getVectorSizeAsInt();
	TTUInt16			i=0;
	TTUInt16			numChannels = out.getNumChannelsAsInt();
	TTUInt16			channel;
	TTUInt64			p1 = (TTUInt64)mIndex;						// playback index

	// Move the play head
	mIndex += (mIndexDelta * vs);

	// Wrap the play head
	if (mIndex >= mSize)
	{
		mIndex -= mSize;
		mBuffer->checkInMatrix(mWavetable);
		mBuffer->checkOutMatrix(mWavetable);
	} else if (mIndex < 0) {
		mIndex += mSize;
		mBuffer->checkInMatrix(mWavetable);
		mBuffer->checkOutMatrix(mWavetable);
	}

	// table lookup (no interpolation)
	// CURRENTLY: this is hard coded to look only at the first channel, and all other channels in the buffer are ignored
	mWavetable->peek(p1,0,tempSample);
	tempSample *= mLinearGain;

	// TODO: in TTBlue 0.2.x this code only assigned the first sample value to save cpu -- should we bring this back as an option?
	while (vs--) {
		for (channel=0; channel<numChannels; channel++)
			out.mSampleVectors[channel][i] = tempSample;
		i++;
	}

	return kTTErrNone;
}

TTErr TTWavetable::processWithNoInterpolation(TTAudioSignalArrayPtr inputs, TTAudioSignalArrayPtr outputs)
{
	TTAudioSignalPtr	in; // can't call getSignal if there is no signal! = inputs->getSignal(0);
	TTAudioSignal&		out = outputs->getSignal(0);
	TTSampleValue		*inSample = NULL;
	TTSampleValue		tempSample;
	TTUInt16			vs = out.getVectorSizeAsInt();
	TTUInt16			i=0;
	TTUInt16			numChannels = out.getNumChannelsAsInt();
	TTUInt16			channel;
	TTBoolean			hasModulation = true;

	// If the input and output signals are the same, then there really isn't an input signal
	// In that case we don't modulate the oscillator with it
	if (inputs->numAudioSignals == 0)
		hasModulation = false;
	else {
		in = &inputs->getSignal(0);
		inSample = in->mSampleVectors[0];
	}
	while (vs--) {
		TTUInt64	p1 = (TTUInt64)mIndex;	// playback index

		// TODO: all of this access of mIndex and mIndexDelta etc is really going to be dereference pointers in our struct/class
		//		 This likely means that the values are not cached (or at least not cached together) in the processors registers
		//		 We should copy these to local variables at the vector start and then copy them back at the vector's end

		// Move the play head
		mIndex += mIndexDelta;

		// Apply modulation to the play head
		if (hasModulation)
			mIndex += *inSample++ * mSize / sr;

		// Wrap the play head
		if (mIndex >= mSize)
		{
			mIndex -= mSize;
			mBuffer->checkInMatrix(mWavetable);
			mBuffer->checkOutMatrix(mWavetable);
		} else if (mIndex < 0) {
			mIndex += mSize;
			mBuffer->checkInMatrix(mWavetable);
			mBuffer->checkOutMatrix(mWavetable);
		}

		// table lookup (no interpolation)
		// CURRENTLY: this is hard coded to look only at the first channel, and all other channels in the buffer are ignored
		mWavetable->peek(p1,0,tempSample);
		tempSample *= mLinearGain;
		for (channel=0; channel<numChannels; channel++)
			out.mSampleVectors[channel][i] = tempSample;
		i++;
	}

	return kTTErrNone;
}

TTErr TTWavetable::processWithLinearInterpolation(TTAudioSignalArrayPtr inputs, TTAudioSignalArrayPtr outputs)
{
	TTAudioSignalPtr	in; // can't call getSignal if there is no signal! = inputs->getSignal(0);
	TTAudioSignal&		out = outputs->getSignal(0);
	TTSampleValue		*inSample = NULL;
	TTSampleValue		tempSample;
	TTUInt16			vs = out.getVectorSizeAsInt();
	TTUInt16			i=0;
	TTUInt16			numChannels = out.getNumChannelsAsInt();
	TTUInt16			channel;
	TTBoolean			hasModulation = true;

	// If the input and output signals are the same, then there really isn't an input signal
	// In that case we don't modulate the oscillator with it
	if (inputs->numAudioSignals == 0)
		hasModulation = false;
	else {
		in = &inputs->getSignal(0);
		inSample = in->mSampleVectors[0];
	}
	while (vs--) {
		// Move the play head
		mIndex += mIndexDelta;

		// Apply modulation to the play head
		if (hasModulation)
			mIndex += *inSample++ * mSize / sr;

		// Wrap the play head
		if (mIndex >= mSize)
		{
			mIndex -= mSize;
			mBuffer->checkInMatrix(mWavetable);
			mBuffer->checkOutMatrix(mWavetable);
		} else if (mIndex < 0) {
			mIndex += mSize;
			mBuffer->checkInMatrix(mWavetable);
			mBuffer->checkOutMatrix(mWavetable);
		}

		// table lookup (linear interpolation)
		// CURRENTLY: this is hard coded to look only at the first channel, and all other channels in the buffer are ignored
		mWavetable->peeki(mIndex,0,tempSample);
		tempSample *= mLinearGain;
		for (channel=0; channel<numChannels; channel++)
			out.mSampleVectors[channel][i] = tempSample;
		i++;
	}

	//mWavetable = contents; // update the class variable
	return kTTErrNone;
}
<commit_msg>trying to access the load() procedure in Max via the j.wavetable object. works, but is unpredictable.<commit_after>/** @file
 *
 * @ingroup dspGeneratorLib
 *
 * @brief GeneratorLib: Generate a basic, cycling waveform using a wavetable.
 *
 * @details Wavetable is currently limited to using an internal buffer for managing its waveshape.  Shape options include sine, triangle and sawtooth.
 *
 * @see TTBuffer, TTSampleMatrix, TTMatrix, TTAudioSignal
 *
 * @authors Tim Place, Nathan Wolek
 *
 * @copyright Copyright © 2003-2013 by Timothy Place & Nathan Wolek @n
 * This code is licensed under the terms of the "New BSD License" @n
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTWavetable.h"

#define thisTTClass			TTWavetable
#define thisTTClassName		"wavetable"
#define thisTTClassTags		"audio, generator, oscillator, buffer"

TT_AUDIO_CONSTRUCTOR,
	mIndex(0.0),
	mIndexDelta(0.0),
	mBuffer(NULL),
	mWavetable(NULL)
{
	TTUInt16	initialMaxNumChannels = arguments;

	addAttributeWithSetter(Frequency,		kTypeFloat64);
	addAttributeWithSetter(Mode,			kTypeSymbol);
	addAttributeWithSetter(Gain,			kTypeFloat64);
	addAttributeWithSetter(Interpolation,	kTypeSymbol);
	addAttributeWithSetter(Size,			kTypeUInt32);

	addUpdates(SampleRate);

	TTObjectBaseInstantiate("buffer", (TTObjectBasePtr*)&mBuffer, kTTValNONE);
	if (!mBuffer)
		throw TTException("Could not create internal buffer object");
	mBuffer->setNumChannels(TTUInt32(1));
	mBuffer->checkOutMatrix(mWavetable);

	// Set Defaults...
	setAttributeValue("maxNumChannels",	initialMaxNumChannels);
	setAttributeValue("size", 8192);
	setAttributeValue("mode", kTTSym_sine);
	setAttributeValue("frequency", 440.0);
	setAttributeValue("gain", 0.0);			// 0 dB
	setAttributeValue("interpolation", "linear");
}

TTWavetable::~TTWavetable()
{
	TTObjectBaseRelease((TTObjectBase**)&mBuffer);
}

TTErr TTWavetable::updateSampleRate(const TTValue&, TTValue&)
{
	setAttributeValue("frequency", mFrequency);
	return kTTErrNone;
}

TTErr TTWavetable::setFrequency(const TTValue& newValue)
{
	mFrequency = TTClip<TTFloat64>(newValue, 0.0, sr/2.0);
	mIndexDelta = mFrequency * mSize * srInv;
	return kTTErrNone;
}

TTErr TTWavetable::setMode(const TTValue& newValue)
{
	mMode = newValue[0];	// TODO: should be newValue[0]

	if (mMode != "externalFile")
		return mBuffer->fill(newValue, kTTValNONE);
	else {
		// TODO: implement the ability to use an externally defined buffer
        TTValue loadInput;
        loadInput.append(TT("/Volumes/Storage/Audio/200604femf15/pitched/ding_b2.aiff"));

        return mBuffer->load(loadInput, kTTValNONE);

		//return kTTErrInvalidValue;
	}
}

TTErr TTWavetable::setInterpolation(const TTValue& newValue)
{
	mMode = newValue;
	if (mMode == "linear")
		setProcessMethod(processWithLinearInterpolation);
	else if (mMode == "lfo")
		setProcessMethod(processAsLFO);
	else
		setProcessMethod(processWithNoInterpolation);
	return kTTErrNone;
}

TTErr TTWavetable::setGain(const TTValue& newValue)
{
	mGain = newValue;
	mLinearGain = TTDecibelsToLinearGain(mGain);
	return kTTErrNone;
}

TTErr TTWavetable::setSize(const TTValue& newSize)
{
	mSize = newSize;
	mBuffer->setLengthInSamples(mSize);
	return setFrequency(mFrequency); // touch the frequency so that the step size is updated
}

// LFO mode only updates values once per vector in order to be as fast as possible
// LFO mode cannot be modulated
TTErr TTWavetable::processAsLFO(TTAudioSignalArrayPtr, TTAudioSignalArrayPtr outputs)
{
	TTAudioSignal&		out = outputs->getSignal(0);
	TTSampleValue		tempSample;
	TTUInt16			vs = out.getVectorSizeAsInt();
	TTUInt16			i=0;
	TTUInt16			numChannels = out.getNumChannelsAsInt();
	TTUInt16			channel;
	TTUInt64			p1 = (TTUInt64)mIndex;						// playback index

	// Move the play head
	mIndex += (mIndexDelta * vs);

	// Wrap the play head
	if (mIndex >= mSize)
	{
		mIndex -= mSize;
		mBuffer->checkInMatrix(mWavetable);
		mBuffer->checkOutMatrix(mWavetable);
	} else if (mIndex < 0) {
		mIndex += mSize;
		mBuffer->checkInMatrix(mWavetable);
		mBuffer->checkOutMatrix(mWavetable);
	}

	// table lookup (no interpolation)
	// CURRENTLY: this is hard coded to look only at the first channel, and all other channels in the buffer are ignored
	mWavetable->peek(p1,0,tempSample);
	tempSample *= mLinearGain;

	// TODO: in TTBlue 0.2.x this code only assigned the first sample value to save cpu -- should we bring this back as an option?
	while (vs--) {
		for (channel=0; channel<numChannels; channel++)
			out.mSampleVectors[channel][i] = tempSample;
		i++;
	}

	return kTTErrNone;
}

TTErr TTWavetable::processWithNoInterpolation(TTAudioSignalArrayPtr inputs, TTAudioSignalArrayPtr outputs)
{
	TTAudioSignalPtr	in; // can't call getSignal if there is no signal! = inputs->getSignal(0);
	TTAudioSignal&		out = outputs->getSignal(0);
	TTSampleValue		*inSample = NULL;
	TTSampleValue		tempSample;
	TTUInt16			vs = out.getVectorSizeAsInt();
	TTUInt16			i=0;
	TTUInt16			numChannels = out.getNumChannelsAsInt();
	TTUInt16			channel;
	TTBoolean			hasModulation = true;

	// If the input and output signals are the same, then there really isn't an input signal
	// In that case we don't modulate the oscillator with it
	if (inputs->numAudioSignals == 0)
		hasModulation = false;
	else {
		in = &inputs->getSignal(0);
		inSample = in->mSampleVectors[0];
	}
	while (vs--) {
		TTUInt64	p1 = (TTUInt64)mIndex;	// playback index

		// TODO: all of this access of mIndex and mIndexDelta etc is really going to be dereference pointers in our struct/class
		//		 This likely means that the values are not cached (or at least not cached together) in the processors registers
		//		 We should copy these to local variables at the vector start and then copy them back at the vector's end

		// Move the play head
		mIndex += mIndexDelta;

		// Apply modulation to the play head
		if (hasModulation)
			mIndex += *inSample++ * mSize / sr;

		// Wrap the play head
		if (mIndex >= mSize)
		{
			mIndex -= mSize;
			mBuffer->checkInMatrix(mWavetable);
			mBuffer->checkOutMatrix(mWavetable);
		} else if (mIndex < 0) {
			mIndex += mSize;
			mBuffer->checkInMatrix(mWavetable);
			mBuffer->checkOutMatrix(mWavetable);
		}

		// table lookup (no interpolation)
		// CURRENTLY: this is hard coded to look only at the first channel, and all other channels in the buffer are ignored
		mWavetable->peek(p1,0,tempSample);
		tempSample *= mLinearGain;
		for (channel=0; channel<numChannels; channel++)
			out.mSampleVectors[channel][i] = tempSample;
		i++;
	}

	return kTTErrNone;
}

TTErr TTWavetable::processWithLinearInterpolation(TTAudioSignalArrayPtr inputs, TTAudioSignalArrayPtr outputs)
{
	TTAudioSignalPtr	in; // can't call getSignal if there is no signal! = inputs->getSignal(0);
	TTAudioSignal&		out = outputs->getSignal(0);
	TTSampleValue		*inSample = NULL;
	TTSampleValue		tempSample;
	TTUInt16			vs = out.getVectorSizeAsInt();
	TTUInt16			i=0;
	TTUInt16			numChannels = out.getNumChannelsAsInt();
	TTUInt16			channel;
	TTBoolean			hasModulation = true;

	// If the input and output signals are the same, then there really isn't an input signal
	// In that case we don't modulate the oscillator with it
	if (inputs->numAudioSignals == 0)
		hasModulation = false;
	else {
		in = &inputs->getSignal(0);
		inSample = in->mSampleVectors[0];
	}
	while (vs--) {
		// Move the play head
		mIndex += mIndexDelta;

		// Apply modulation to the play head
		if (hasModulation)
			mIndex += *inSample++ * mSize / sr;

		// Wrap the play head
		if (mIndex >= mSize)
		{
			mIndex -= mSize;
			mBuffer->checkInMatrix(mWavetable);
			mBuffer->checkOutMatrix(mWavetable);
		} else if (mIndex < 0) {
			mIndex += mSize;
			mBuffer->checkInMatrix(mWavetable);
			mBuffer->checkOutMatrix(mWavetable);
		}

		// table lookup (linear interpolation)
		// CURRENTLY: this is hard coded to look only at the first channel, and all other channels in the buffer are ignored
		mWavetable->peeki(mIndex,0,tempSample);
		tempSample *= mLinearGain;
		for (channel=0; channel<numChannels; channel++)
			out.mSampleVectors[channel][i] = tempSample;
		i++;
	}

	//mWavetable = contents; // update the class variable
	return kTTErrNone;
}
<|endoftext|>