// $Id: ITASampleBuffer.cpp 4124 2015-07-14 13:00:26Z fwefers $ #include #include #include #include #include #include #include #include #include //#define FM_XSIZE(V, F) V = F * (V%F ? (V/F)+1 : V/F); //! C-related sample field mathematical operations /* namespace CRels { inline void fm_set(float* buf, float value, unsigned int count) { for (unsigned int i = 0; i= 0 ); Free(); size_t iBytes = size_t( iLength*sizeof(float) ); #ifdef __GNUC__ // TODO: Für den g++ erstmal kein aligned malloc m_pfData = (float*)malloc(iBytes); #else m_pfData = (float*)_aligned_malloc(iBytes, 16); #endif m_iLength = iLength; } void ITASampleBuffer::Free() { #ifdef __GNUC__ if (m_pfData) free(m_pfData); // unaligned #else if (m_pfData) _aligned_free( m_pfData ); #endif m_pfData = NULL; m_iLength = 0; } bool ITASampleBuffer::IsEmpty() const { return (m_iLength == 0); } int ITASampleBuffer::GetLength() const { return m_iLength; } const float* ITASampleBuffer::GetData() const { return m_pfData; } float* ITASampleBuffer::GetData() { return m_pfData; } void ITASampleBuffer::Fill(float fValue) { fm_set(m_pfData, fValue, m_iLength); } void ITASampleBuffer::Fill(int iOffset, int iCount, float fValue) { if ((iOffset < 0) || (iOffset >= m_iLength)) ITA_EXCEPT1(INVALID_PARAMETER, "Offset out of range"); if ((iCount < 0) || (iOffset+iCount > m_iLength)) ITA_EXCEPT1(INVALID_PARAMETER, "Count out of range"); // TODO: Schnelle Implementierung? for (int i=iOffset; i= 0 ); assert( iCount > 0 ); assert( (iOffset+iCount) <= m_iLength ); int iFlags = 0; switch (iFadeDirection) { case FADE_IN: iFlags |= ITA_FADE_IN; break; case FADE_OUT: iFlags |= ITA_FADE_OUT; break; default: // Ungültiger Wert assert( false ); } switch (iFadeFunction) { case LINEAR: iFlags |= ITA_FADE_LINEAR; break; case COSINE_SQUARE: iFlags |= ITA_FADE_COSINE_SQUARE; break; default: // Ungültiger Wert assert( false ); } ::Fade(m_pfData + iOffset, iCount, iFlags); } void ITASampleBuffer::Crossfade(const ITASampleBuffer* psbSrc, int iOffset, int iCount, int iFadeDirection, int iFadeFunction) { assert( psbSrc ); assert( iOffset >= 0 ); assert( iCount >= 0 ); assert( (iOffset+iCount) <= m_iLength ); assert( (iOffset+iCount) <= psbSrc->m_iLength ); int iFlags = 0; switch (iFadeFunction) { case LINEAR: iFlags |= ITA_FADE_LINEAR; break; case COSINE_SQUARE: iFlags |= ITA_FADE_COSINE_SQUARE; break; default: // Ungültiger Wert assert( false ); } switch (iFadeDirection) { case CROSSFADE_FROM_SOURCE: // Samples am Anfang kopieren for (int i=0; im_pfData[i]; ::Crossfade(psbSrc->m_pfData + iOffset, m_pfData + iOffset, m_pfData + iOffset, iCount, iFlags); return; case CROSSFADE_TO_SOURCE: assert( psbSrc->m_iLength >= m_iLength ); ::Crossfade(m_pfData + iOffset, psbSrc->m_pfData + iOffset, m_pfData + iOffset, iCount, iFlags); // Samples am Ende kopieren for (int i=iOffset+iCount; im_pfData[i]; return; default: // Ungültiger Wert assert( false ); } } void ITASampleBuffer::Crossfade(const ITASampleBuffer& sbSrc, int iOffset, int iCount, int iFadeDirection, int iFadeFunction) { Crossfade(&sbSrc, iOffset, iCount, iFadeDirection, iFadeFunction); } void ITASampleBuffer::Envelope(float fGain0, float fGain1) { if (IsEmpty()) return; // Linear interpolation float m = (fGain1 - fGain0) / m_iLength; for (int i=0; i= 0 ); assert( (iSrcOffset >= 0) ); assert( (iSrcOffset + iCount) <= m_iLength ); // TODO: Erkennung von MemoryAlignment und schnelle SSE-Variante? memcpy(pfDest, m_pfData + iSrcOffset, iCount * sizeof(float)); } void ITASampleBuffer::write(const float* pfSrc, int iCount, int iDestOffset) { assert( pfSrc != NULL ); assert( iCount >= 0 ); assert( (iDestOffset >= 0) ); assert( (iDestOffset + iCount) <= m_iLength ); // TODO: Erkennung von MemoryAlignment und schnelle SSE-Variante? memcpy(m_pfData + iDestOffset, pfSrc, iCount * sizeof(float)); } void ITASampleBuffer::write(const ITASampleBuffer* psbSrc, int iCount, int iSrcOffset, int iDestOffset) { assert( psbSrc != NULL ); assert( iCount >= 0 ); assert( (iSrcOffset >= 0) ); assert( (iSrcOffset + iCount) <= psbSrc->GetLength() ); assert( (iDestOffset + iCount) <= m_iLength ); // TODO: Erkennung von MemoryAlignment und schnelle SSE-Variante? memcpy(m_pfData + iDestOffset, psbSrc->GetData() + iSrcOffset, iCount * sizeof(float)); } void ITASampleBuffer::write(const ITASampleBuffer& sbSrc, int iCount, int iSrcOffset, int iDestOffset) { write(&sbSrc, iCount, iSrcOffset, iDestOffset); } void ITASampleBuffer::cyclic_read(float* pfDest, int iCount, int iSrcOffset) const { assert( pfDest != NULL ); assert( iCount >= 0 ); assert( (iSrcOffset >= 0) && (iSrcOffset < m_iLength) ); int n = 0; // Anzahl kopierter Samples int p = ((iSrcOffset % m_iLength) + m_iLength) % m_iLength; // Leseposition while (n < iCount) { // Verbleibende Samples berechnen int r = std::min(iCount - n, m_iLength - p); read(pfDest+n, r, p); p = (p+r) % m_iLength; n += r; } } void ITASampleBuffer::cyclic_write(const float* pfSrc, int iCount, int iDestOffset) { assert( pfSrc != NULL ); assert( iCount >= 0 ); int n = 0; // Anzahl kopierter Samples int p = ((iDestOffset % m_iLength) + m_iLength) % m_iLength; // Schreibposition while (n < iCount) { // Verbleibende Samples berechnen int r = std::min(iCount - n, m_iLength - p); write(pfSrc+n, r, p); p = (p+r) % m_iLength; n += r; } } void ITASampleBuffer::cyclic_write(const ITASampleBuffer* psbSrc, int iCount, int iSrcOffset, int iDestOffset) { assert( psbSrc != NULL ); assert( iCount >= 0 ); int iSrcLength = psbSrc->GetLength(); int n = 0; // Anzahl kopierter Samples // Beliebige Offsets werden in das positive Intervall abgebildet int p = ((iSrcOffset % iSrcLength) + iSrcLength) % iSrcLength; // Leseposition int q = ((iDestOffset % m_iLength) + m_iLength) % m_iLength; // Schreibposition while (n < iCount) { // Verbleibende Samples berechnen int rs = iSrcLength - p; int rd = m_iLength - q; int r = std::min(iCount - n, std::min(rs, rd)); write(psbSrc, r, p, q); p = (p+r) % iSrcLength; q = (q+r) % m_iLength; n += r; } } void ITASampleBuffer::cyclic_write(const ITASampleBuffer& sbSrc, int iCount, int iSrcOffset, int iDestOffset) { cyclic_write(&sbSrc, iCount, iSrcOffset, iDestOffset); } void ITASampleBuffer::CyclicShift(int iCount) { if (iCount >= GetLength()) ITA_EXCEPT1(INVALID_PARAMETER, "Shifting by a count greater than buffer length not allowed"); ITASampleBuffer sbTemp(this); cyclic_write(sbTemp, GetLength(), iCount); } void ITASampleBuffer::add_scalar(float fValue) { // Invariante if (fValue == 0) return; // TODO: Schnelle Implementierung? for (int i=0; iGetLength()); } void ITASampleBuffer::add_buf(const ITASampleBuffer* pSource, const int iCount) { if (!pSource) ITA_EXCEPT1(INVALID_PARAMETER, "Nullpointer passed"); if (pSource->GetLength() < iCount) ITA_EXCEPT1(INVALID_PARAMETER, "Lengths of source buffer too small"); if (m_iLength < iCount) ITA_EXCEPT1(INVALID_PARAMETER, "Requested lengths of source buffer too big to fit into target buffer"); fm_add(m_pfData, pSource->GetData(), iCount); } void ITASampleBuffer::add_buf_pos( const ITASampleBuffer* pSource, const int iPos ) // TODO: move this to add_buf(mit offset=0) { if (!pSource) ITA_EXCEPT1(INVALID_PARAMETER, "Nullpointer passed"); //if (pSource->GetLength() < iCount) ITA_EXCEPT1(INVALID_PARAMETER, "Lengths of source buffer too small"); if ((pSource->m_iLength+iPos) > m_iLength) ITA_EXCEPT1(INVALID_PARAMETER, "Source length + delay exceed length of filter"); fm_add(&(m_pfData[iPos]), pSource->GetData(), pSource->GetLength()); } void ITASampleBuffer::add_buf_pos( float* fSource,const int iSize, const int iPos ) { if (!fSource) ITA_EXCEPT1(INVALID_PARAMETER, "Nullpointer passed"); if (m_iLength < iPos+iSize) ITA_EXCEPT1(INVALID_PARAMETER, "Source length + delay exceed length of filter"); fm_add(&(m_pfData[iPos]), fSource, iSize); } void ITASampleBuffer::sub_buf(const ITASampleBuffer* pSource) { if (!pSource) ITA_EXCEPT1(INVALID_PARAMETER, "Nullpointer passed"); if (pSource->GetLength() != m_iLength) ITA_EXCEPT1(INVALID_PARAMETER, "Block lengths do not match"); fm_sub(m_pfData, pSource->GetData(), m_iLength); } void ITASampleBuffer::mul_buf(const ITASampleBuffer* pSource) { if (!pSource) ITA_EXCEPT1(INVALID_PARAMETER, "Nullpointer passed"); if (pSource->GetLength() != m_iLength) ITA_EXCEPT1(INVALID_PARAMETER, "Block lengths do not match"); // TODO: Schnelle Implementierung? const float* pfSourceData = pSource->GetData(); for (int i=0; iGetLength() != m_iLength) ITA_EXCEPT1(INVALID_PARAMETER, "Block lengths do not match"); // TODO: Schnelle Implementierung? // TODO: Was wenn Division durch Null? const float* pfSourceData = pSource->GetData(); for (int i=0; i pSource->GetLength()) ITA_EXCEPT1(INVALID_PARAMETER, "Source range exceeds source buffer"); if ((iDestOffset + iCount) > m_iLength) ITA_EXCEPT1(INVALID_PARAMETER, "Destination range exceeds destination buffer"); // Spezialfall: Count = 0 => Nichts zu tun if (iCount == 0) return; // Spezialfall: Skalar = 0 => Nichts zu tun if (fScalar == 0) return; for (int i=0; im_pfData[iSrcOffset+i] * fScalar); } void ITASampleBuffer::MulAdd(const ITASampleBuffer& sbSource, float fScalar, int iSrcOffset, int iDestOffset, int iCount) { MulAdd( &sbSource, fScalar, iSrcOffset, iDestOffset, iCount ); } float ITASampleBuffer::FindPeak(int* piPeakIndex) { if (m_iLength == 0) { if (piPeakIndex) *piPeakIndex = 0; return 0; } float fPeak = 0; int iPeakIndex = 0; // TODO: Schnelle Implementierung? (SSE3?) for (int i=0; i fPeak) { fPeak = x; iPeakIndex = i; } } if (piPeakIndex) *piPeakIndex = iPeakIndex; return fPeak; } void ITASampleBuffer::Negate() { mul_scalar(-1); }; float& ITASampleBuffer::operator[](int iSample) { return m_pfData[iSample]; } const float& ITASampleBuffer::operator[](int iSample) const { return m_pfData[iSample]; } ITASampleBuffer& ITASampleBuffer::operator=(const ITASampleBuffer& rhs) { // Selbstzuweisung abfangen if (&rhs == this) return *this; if (m_pParent) { ITA_EXCEPT1(MODAL_EXCEPTION, "Assignment impossible. Would change length, but sample buffer is part of a parent sample frame."); } // Schnelle Abkürzung if (rhs.IsEmpty()) { Free(); return *this; } if ((m_iLength != rhs.m_iLength)) { // Neu allozieren Init( rhs.GetLength(), false ); } // Samples kopieren fm_copy(m_pfData, rhs.GetData(), m_iLength); return *this; } ITASampleBuffer& ITASampleBuffer::operator+=(const float rhs) { add_scalar(rhs); return *this; } ITASampleBuffer& ITASampleBuffer::operator-=(const float rhs) { sub_scalar(rhs); return *this; } ITASampleBuffer& ITASampleBuffer::operator*=(const float rhs) { mul_scalar(rhs); return *this; } ITASampleBuffer& ITASampleBuffer::operator/=(const float rhs) { div_scalar(rhs); return *this; } ITASampleBuffer& ITASampleBuffer::operator+=(const ITASampleBuffer& rhs) { add_buf(rhs); return *this; } ITASampleBuffer& ITASampleBuffer::operator-=(const ITASampleBuffer& rhs) { sub_buf(rhs); return *this; } ITASampleBuffer& ITASampleBuffer::operator*=(const ITASampleBuffer& rhs) { mul_buf(rhs); return *this; } ITASampleBuffer& ITASampleBuffer::operator/=(const ITASampleBuffer& rhs) { div_buf(rhs); return *this; } std::string ITASampleBuffer::toString() const { std::stringstream ss; ss << "Sample buffer { "; if (IsEmpty()) ss << "emtpy"; else ss << m_iLength << " samples"; ss << " }"; return ss.str(); }