From 47c6ba708fcfaf4dae9d943078dfeaa2c7f49b55 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 20 Sep 2014 04:45:58 -0700 Subject: [PATCH] new audio edit buffer object / click removal / apply linear fade to sound clip endpoints --- libraries/audio/src/AudioEditBuffer.h | 108 ++++++++++++++++++++++++++ libraries/audio/src/Sound.cpp | 25 +++++- libraries/audio/src/Sound.h | 1 + 3 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 libraries/audio/src/AudioEditBuffer.h diff --git a/libraries/audio/src/AudioEditBuffer.h b/libraries/audio/src/AudioEditBuffer.h new file mode 100644 index 0000000000..1fa2794e79 --- /dev/null +++ b/libraries/audio/src/AudioEditBuffer.h @@ -0,0 +1,108 @@ +// +// AudioEditBuffer.h +// hifi +// +// Created by Craig Hansen-Sturm on 8/29/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AudioEditBuffer_h +#define hifi_AudioEditBuffer_h + +template< typename T > +class AudioEditBuffer + : public AudioFrameBuffer { + +public: + + AudioEditBuffer() : + AudioFrameBuffer() { + } + + AudioEditBuffer(const uint32_t channelCount, const uint32_t frameCount) : + AudioFrameBuffer(channelCount, frameCount) { + } + + ~AudioEditBuffer() { + } + + bool getZeroCrossing(uint32_t start, bool direction, float32_t epsilon, uint32_t& zero); + + void linearFade(uint32_t start, uint32_t stop, bool slope); + void exponentialFade(uint32_t start, uint32_t stop, bool slope); +}; + +template< typename T > +bool AudioEditBuffer::getZeroCrossing(uint32_t start, bool direction, float32_t epsilon, uint32_t& zero) { + + zero = this->_frameCount; + + if (direction) { // scan from the left + if (start < this->_frameCount) { + for (uint32_t i = start; i < this->_frameCount; ++i) { + for (uint32_t j = 0; j < this->_channelCount; ++j) { + if (this->_frameBuffer[j][i] >= -epsilon && this->_frameBuffer[j][i] <= epsilon) { + zero = i; + return true; + } + } + } + } + } + else { // scan from the right + if (start != 0 && start < this->_frameCount) { + for (uint32_t i = start; i != 0; --i) { + for (uint32_t j = 0; j < this->_channelCount; ++j) { + if (this->_frameBuffer[j][i] >= -epsilon && this->_frameBuffer[j][i] <= epsilon) { + zero = i; + return true; + } + } + } + } + } + + return false; +} + +template< typename T > +void AudioEditBuffer::linearFade(uint32_t start, uint32_t stop, bool slope) { + + if (start >= stop || start > this->_frameCount || stop > this->_frameCount ) { + return; + } + + uint32_t count = stop - start; + float32_t delta; + float32_t gain; + + if (slope) { // 0.0 to 1.0f in delta increments + delta = 1.0f / (float32_t)count; + gain = 0.0f; + } + else { // 1.0f to 0.0f in delta increments + delta = -1.0f / (float32_t)count; + gain = 1.0f; + } + + for (uint32_t i = start; i < stop; ++i) { + for (uint32_t j = 0; j < this->_channelCount; ++j) { + this->_frameBuffer[j][i] *= gain; + gain += delta; + } + } +} + +template< typename T > +void AudioEditBuffer::exponentialFade(uint32_t start, uint32_t stop, bool slope) { + // TBD +} + +typedef AudioEditBuffer< float32_t > AudioEditBufferFloat32; +typedef AudioEditBuffer< int32_t > AudioEditBufferSInt32; + +#endif // hifi_AudioEditBuffer_h + diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index f52f5c04dd..9edb04aa2c 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -24,6 +24,9 @@ #include #include "AudioRingBuffer.h" +#include "AudioFormat.h" +#include "AudioBuffer.h" +#include "AudioEditBuffer.h" #include "Sound.h" // procedural audio version of Sound @@ -120,6 +123,7 @@ void Sound::replyFinished() { // Process as RAW file downSample(rawAudioByteArray); } + trimFrames(); } else { qDebug() << "Network reply without 'Content-Type'."; } @@ -133,7 +137,6 @@ void Sound::replyError(QNetworkReply::NetworkError code) { } void Sound::downSample(const QByteArray& rawAudioByteArray) { - // assume that this was a RAW file and is now an array of samples that are // signed, 16-bit, 48Khz, mono @@ -155,6 +158,26 @@ void Sound::downSample(const QByteArray& rawAudioByteArray) { } } +void Sound::trimFrames() { + + const uint32_t inputFrameCount = _byteArray.size() / sizeof(int16_t); + const uint32_t trimCount = 1024; // number of leading and trailing frames to trim + + if (inputFrameCount <= (2 * trimCount)) { + return; + } + + int16_t* inputFrameData = (int16_t*)_byteArray.data(); + + AudioEditBufferFloat32 editBuffer(1, inputFrameCount); + editBuffer.copyFrames(1, inputFrameCount, inputFrameData, false /*copy in*/); + + editBuffer.linearFade(0, trimCount, true); + editBuffer.linearFade(inputFrameCount - trimCount, inputFrameCount, false); + + editBuffer.copyFrames(1, inputFrameCount, inputFrameData, true /*copy out*/); +} + // // Format description from https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ // diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index 7dae3679f1..fa2dd97903 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -33,6 +33,7 @@ private: QByteArray _byteArray; bool _hasDownloaded; + void trimFrames(); void downSample(const QByteArray& rawAudioByteArray); void interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray);