From 9369f15a3e38069fdf580d3a6ed5430b72eb51d3 Mon Sep 17 00:00:00 2001 From: justburner Date: Feb 27 2022 22:42:01 +0000 Subject: Audio fixes and enhancements --- diff --git a/toonz/sources/common/tsound/tsop.cpp b/toonz/sources/common/tsound/tsop.cpp index f3a3678..aafbb2d 100644 --- a/toonz/sources/common/tsound/tsop.cpp +++ b/toonz/sources/common/tsound/tsop.cpp @@ -394,8 +394,12 @@ dstSample += tmp; // assert(dstSample.getValue(0) == dstChannel[0]); } + // Removed tround() since it was destroying 32-bits float data + // for (int i = 0; i < src.getChannelCount(); i++) + // dstSample.setValue(i, (ChannelValueType)(tround(dstChannel[i]))); + for (int i = 0; i < src.getChannelCount(); i++) - dstSample.setValue(i, (ChannelValueType)(tround(dstChannel[i]))); + dstSample.setValue(i, (ChannelValueType)(dstChannel[i])); *(dst->samples() + id) = dstSample; @@ -483,6 +487,21 @@ public: return TSoundTrackP(dst); } + + TSoundTrackP compute(const TSoundTrackMono32Float &src) override { + TSoundTrackMono32Float *dst = resampleT( + const_cast(src), m_sampleRate, m_filterType); + + return TSoundTrackP(dst); + } + + TSoundTrackP compute(const TSoundTrackStereo32Float &src) override { + TSoundTrackStereo32Float *dst = + resampleT(const_cast(src), m_sampleRate, + m_filterType); + + return TSoundTrackP(dst); + } }; //============================================================================== @@ -559,6 +578,20 @@ TSoundTrackP doConvertWithoutResamplingT(SRC *src, return dstS24; } + TSoundTrackMono32Float *dstM32F = + dynamic_cast(dst.getPointer()); + if (dstM32F) { + convertSamplesT(*dstM32F, *src); + return dstM32F; + } + + TSoundTrackStereo32Float *dstS32F = + dynamic_cast(dst.getPointer()); + if (dstS32F) { + convertSamplesT(*dstS32F, *src); + return dstS32F; + } + return 0; } @@ -596,6 +629,7 @@ public: TSoundTrackP compute(const TSoundTrackStereo16 &src) override { return doConvertWithoutResamplingT(&src, m_format); } + TSoundTrackP compute(const TSoundTrackMono24 &src) override { return doConvertWithoutResamplingT(&src, m_format); } @@ -603,6 +637,14 @@ public: TSoundTrackP compute(const TSoundTrackStereo24 &src) override { return doConvertWithoutResamplingT(&src, m_format); } + + TSoundTrackP compute(const TSoundTrackMono32Float &src) override { + return doConvertWithoutResamplingT(&src, m_format); + } + + TSoundTrackP compute(const TSoundTrackStereo32Float &src) override { + return doConvertWithoutResamplingT(&src, m_format); + } }; //----------------------------------------------------------------------------- @@ -705,7 +747,8 @@ void TSop::convert(TSoundTrackP &dst, const TSoundTrackP &src) { bitPerSample = dst->getBitPerSample(); tmp = TSoundTrack::create((int)src->getSampleRate(), bitPerSample, chans, - src_reslen * src->getSampleSize()); + src_reslen * src->getSampleSize(), + src->getSampleType()); convertWithoutResampling(tmp, src); tmq = TSop::resample(tmp, (TINT32)dst->getSampleRate()); @@ -726,7 +769,7 @@ void TSop::convert(TSoundTrackP &dst, const TSoundTrackP &src) { tmp = TSoundTrack::create((int)src->getSampleRate(), dst->getBitPerSample(), dst->getChannelCount(), src_reslen * dst->getSampleSize(), - dst->isSampleSigned()); + dst->getSampleType()); convertWithoutResampling(tmp, src); dst = TSop::resample(tmp, (TINT32)dst->getSampleRate()); @@ -844,6 +887,16 @@ public: return doReverb(const_cast(&src), m_delayTime, m_decayFactor, m_extendTime); } + + TSoundTrackP compute(const TSoundTrackMono32Float &src) override { + return doReverb(const_cast(&src), m_delayTime, + m_decayFactor, m_extendTime); + } + + TSoundTrackP compute(const TSoundTrackStereo32Float &src) override { + return doReverb(const_cast(&src), m_delayTime, + m_decayFactor, m_extendTime); + } }; //============================================================================== @@ -951,6 +1004,16 @@ public: return doGate(const_cast(&src), m_threshold, m_holdTime, m_releaseTime); } + + TSoundTrackP compute(const TSoundTrackMono32Float &src) override { + return doGate(const_cast(&src), m_threshold, + m_holdTime, m_releaseTime); + } + + TSoundTrackP compute(const TSoundTrackStereo32Float &src) override { + return doGate(const_cast(&src), m_threshold, + m_holdTime, m_releaseTime); + } }; //============================================================================== @@ -1104,6 +1167,23 @@ void TSop::echo(TSoundTrackP &dst, const TSoundTrackP &src, double delayTime, srcS24 = dynamic_cast(src.getPointer()); if (srcS24) dst = doEcho(srcS24, delayTime, decayFactor, extendTime); + else { + TSoundTrackMono32Float *srcM32F; + srcM32F = + dynamic_cast(src.getPointer()); + if (srcM32F) + dst = doEcho(srcM32F, delayTime, decayFactor, extendTime); + else { + TSoundTrackStereo32Float *srcS32F; + srcS32F = dynamic_cast( + src.getPointer()); + if (srcS32F) + dst = doEcho(srcS32F, delayTime, decayFactor, extendTime); + // Yo Dawg, I herd you like nesting ifs, so I put an nest if + // in your nesting ifs so you can nest if while you nesting + // ifs + } + } } } } @@ -1129,7 +1209,7 @@ TSoundTrackP TSop::insertBlank(TSoundTrackP src, TINT32 s0, TINT32 len) { int bytePerSample = dst->getSampleSize(); memcpy(dstRawData, srcRawData, ss0 * bytePerSample); - if (format.m_signedSample) + if (format.m_sampleType != TSound::UINT) memset(dstRawData + ss0 * bytePerSample, 0, len * bytePerSample); else memset(dstRawData + ss0 * bytePerSample, 127, len * bytePerSample); @@ -1297,6 +1377,24 @@ public: dynamic_cast(m_sndtrack.getPointer()), m_alpha2)); } + + TSoundTrackP compute(const TSoundTrackMono32Float &src) override { + assert(src.getFormat() == m_sndtrack->getFormat()); + + return ( + mixT(const_cast(&src), m_alpha1, + dynamic_cast(m_sndtrack.getPointer()), + m_alpha2)); + } + + TSoundTrackP compute(const TSoundTrackStereo32Float &src) override { + assert(src.getFormat() == m_sndtrack->getFormat()); + + return ( + mixT(const_cast(&src), m_alpha1, + dynamic_cast(m_sndtrack.getPointer()), + m_alpha2)); + } }; TSoundTrackP TSop::mix(const TSoundTrackP &st1, const TSoundTrackP &st2, @@ -1373,6 +1471,8 @@ public: TSoundTrackP compute(const TSoundTrackStereo16 &) override; TSoundTrackP compute(const TSoundTrackMono24 &) override; TSoundTrackP compute(const TSoundTrackStereo24 &) override; + TSoundTrackP compute(const TSoundTrackMono32Float &) override; + TSoundTrackP compute(const TSoundTrackStereo32Float &) override; double m_riseFactor; }; @@ -1428,6 +1528,19 @@ TSoundTrackP TSoundTrackFaderIn::compute(const TSoundTrackStereo24 &track) { //------------------------------------------------------------------------------ +TSoundTrackP TSoundTrackFaderIn::compute(const TSoundTrackMono32Float &track) { + return doFadeIn(track, m_riseFactor); +} + +//------------------------------------------------------------------------------ + +TSoundTrackP TSoundTrackFaderIn::compute( + const TSoundTrackStereo32Float &track) { + return doFadeIn(track, m_riseFactor); +} + +//------------------------------------------------------------------------------ + TSoundTrackP TSop::fadeIn(const TSoundTrackP src, double riseFactor) { TSoundTrackFaderIn *fader = new TSoundTrackFaderIn(riseFactor); TSoundTrackP out = src->apply(fader); @@ -1495,6 +1608,8 @@ public: TSoundTrackP compute(const TSoundTrackStereo16 &) override; TSoundTrackP compute(const TSoundTrackMono24 &) override; TSoundTrackP compute(const TSoundTrackStereo24 &) override; + TSoundTrackP compute(const TSoundTrackMono32Float &) override; + TSoundTrackP compute(const TSoundTrackStereo32Float &) override; double m_decayFactor; }; @@ -1542,6 +1657,7 @@ TSoundTrackP TSoundTrackFaderOut::compute(const TSoundTrackStereo16 &track) { TSoundTrackP TSoundTrackFaderOut::compute(const TSoundTrackMono24 &track) { return doFadeOut(track, m_decayFactor); } + //------------------------------------------------------------------------------ TSoundTrackP TSoundTrackFaderOut::compute(const TSoundTrackStereo24 &track) { @@ -1550,6 +1666,19 @@ TSoundTrackP TSoundTrackFaderOut::compute(const TSoundTrackStereo24 &track) { //------------------------------------------------------------------------------ +TSoundTrackP TSoundTrackFaderOut::compute(const TSoundTrackMono32Float &track) { + return doFadeOut(track, m_decayFactor); +} + +//------------------------------------------------------------------------------ + +TSoundTrackP TSoundTrackFaderOut::compute( + const TSoundTrackStereo32Float &track) { + return doFadeOut(track, m_decayFactor); +} + +//------------------------------------------------------------------------------ + TSoundTrackP TSop::fadeOut(const TSoundTrackP src, double decayFactor) { TSoundTrackFaderOut *fader = new TSoundTrackFaderOut(decayFactor); TSoundTrackP out = src->apply(fader); @@ -1627,6 +1756,8 @@ public: TSoundTrackP compute(const TSoundTrackStereo16 &) override; TSoundTrackP compute(const TSoundTrackMono24 &) override; TSoundTrackP compute(const TSoundTrackStereo24 &) override; + TSoundTrackP compute(const TSoundTrackMono32Float &) override; + TSoundTrackP compute(const TSoundTrackStereo32Float &) override; TSoundTrackP m_st; double m_crossFactor; @@ -1707,6 +1838,25 @@ TSoundTrackP TSoundTrackCrossFader::compute(const TSoundTrackStereo24 &src) { //------------------------------------------------------------------------------ +TSoundTrackP TSoundTrackCrossFader::compute(const TSoundTrackMono32Float &src) { + assert(src.getFormat() == m_st->getFormat()); + return doCrossFade(src, + dynamic_cast(m_st.getPointer()), + m_crossFactor); +} + +//------------------------------------------------------------------------------ + +TSoundTrackP TSoundTrackCrossFader::compute( + const TSoundTrackStereo32Float &src) { + assert(src.getFormat() == m_st->getFormat()); + return doCrossFade( + src, dynamic_cast(m_st.getPointer()), + m_crossFactor); +} + +//------------------------------------------------------------------------------ + TSoundTrackP TSop::crossFade(const TSoundTrackP src1, const TSoundTrackP src2, double crossFactor) { TSoundTrackCrossFader *fader = new TSoundTrackCrossFader(src2, crossFactor); @@ -1793,6 +1943,8 @@ public: TSoundTrackP compute(const TSoundTrackStereo16 &) override; TSoundTrackP compute(const TSoundTrackMono24 &) override; TSoundTrackP compute(const TSoundTrackStereo24 &) override; + TSoundTrackP compute(const TSoundTrackMono32Float &) override; + TSoundTrackP compute(const TSoundTrackStereo32Float &) override; TSoundTrackP m_st; double m_crossFactor; @@ -1878,6 +2030,26 @@ TSoundTrackP TSoundTrackCrossFaderOverWrite::compute( //------------------------------------------------------------------------------ +TSoundTrackP TSoundTrackCrossFaderOverWrite::compute( + const TSoundTrackMono32Float &src) { + assert(src.getFormat() == m_st->getFormat()); + return doCrossFadeOverWrite( + src, dynamic_cast(m_st.getPointer()), + m_crossFactor); +} + +//------------------------------------------------------------------------------ + +TSoundTrackP TSoundTrackCrossFaderOverWrite::compute( + const TSoundTrackStereo32Float &src) { + assert(src.getFormat() == m_st->getFormat()); + return doCrossFadeOverWrite( + src, dynamic_cast(m_st.getPointer()), + m_crossFactor); +} + +//------------------------------------------------------------------------------ + TSoundTrackP TSop::crossFade(double crossFactor, const TSoundTrackP src1, const TSoundTrackP src2) { TSoundTrackCrossFaderOverWrite *fader = diff --git a/toonz/sources/common/tsound/tsound.cpp b/toonz/sources/common/tsound/tsound.cpp index 5512466..92eefea 100644 --- a/toonz/sources/common/tsound/tsound.cpp +++ b/toonz/sources/common/tsound/tsound.cpp @@ -10,6 +10,8 @@ #define TRK_S16 18 #define TRK_M24 25 #define TRK_S24 26 +#define TRK_M32 33 +#define TRK_S32 34 //============================================================================== @@ -26,8 +28,7 @@ TSoundTrack::TSoundTrack() //------------------------------------------------------------------------------ TSoundTrack::TSoundTrack(TUINT32 sampleRate, int bitPerSample, int channelCount, - int sampleSize, TINT32 sampleCount, - bool isSampleSigned) + int sampleSize, TINT32 sampleCount, int sampleType) : TSmartObject(m_classCode) , m_sampleRate(sampleRate) @@ -41,7 +42,7 @@ TSoundTrack::TSoundTrack(TUINT32 sampleRate, int bitPerSample, int channelCount, if (!m_buffer) return; // m_buffer = new UCHAR[sampleCount*m_sampleSize]; - if (isSampleSigned) + if (sampleType != TSound::UINT) memset(m_buffer, 0, sampleCount * sampleSize); else memset(m_buffer, 127, sampleCount * sampleSize); @@ -50,8 +51,8 @@ TSoundTrack::TSoundTrack(TUINT32 sampleRate, int bitPerSample, int channelCount, //------------------------------------------------------------------------------ TSoundTrack::TSoundTrack(TUINT32 sampleRate, int bitPerSample, int channelCount, - int sampleSize, TINT32 sampleCount, UCHAR *buffer, - TSoundTrack *parent) + int sampleSize, TINT32 sampleCount, int sampleType, + UCHAR *buffer, TSoundTrack *parent) : TSmartObject(m_classCode) , m_sampleRate(sampleRate) @@ -59,6 +60,7 @@ TSoundTrack::TSoundTrack(TUINT32 sampleRate, int bitPerSample, int channelCount, , m_bitPerSample(bitPerSample) , m_sampleCount(sampleCount) , m_channelCount(channelCount) + , m_sampleType(sampleType) , m_parent(parent) , m_buffer(buffer) , m_bufferOwner(false) { @@ -77,41 +79,57 @@ TSoundTrack::~TSoundTrack() { TSoundTrackP TSoundTrack::create(TUINT32 sampleRate, int bitPerSample, int channelCount, TINT32 sampleCount, - bool signedSample) { - TSoundTrackP st; + int sampleType) { + TSoundTrackP st = 0; int type = bitPerSample + channelCount; switch (type) { case TRK_M8: - if (signedSample) + if (sampleType == TSound::INT) st = new TSoundTrackMono8Signed(sampleRate, channelCount, sampleCount); - else + else if (sampleType == TSound::UINT) st = new TSoundTrackMono8Unsigned(sampleRate, channelCount, sampleCount); break; + case TRK_S8: - if (signedSample) + if (sampleType == TSound::INT) st = new TSoundTrackStereo8Signed(sampleRate, channelCount, sampleCount); - else + else if (sampleType == TSound::UINT) st = new TSoundTrackStereo8Unsigned(sampleRate, channelCount, sampleCount); break; case TRK_M16: - st = new TSoundTrackMono16(sampleRate, channelCount, sampleCount); + if (sampleType == TSound::INT) + st = new TSoundTrackMono16(sampleRate, channelCount, sampleCount); break; case TRK_S16: - st = new TSoundTrackStereo16(sampleRate, channelCount, sampleCount); + if (sampleType == TSound::INT) + st = new TSoundTrackStereo16(sampleRate, channelCount, sampleCount); break; case TRK_M24: - st = new TSoundTrackMono24(sampleRate, channelCount, sampleCount); + if (sampleType == TSound::INT) + st = new TSoundTrackMono24(sampleRate, channelCount, sampleCount); break; case TRK_S24: - st = new TSoundTrackStereo24(sampleRate, channelCount, sampleCount); + if (sampleType == TSound::INT) + st = new TSoundTrackStereo24(sampleRate, channelCount, sampleCount); break; - default: + case TRK_M32: + if (sampleType == TSound::FLOAT) + st = new TSoundTrackMono32Float(sampleRate, channelCount, sampleCount); + break; + + case TRK_S32: + if (sampleType == TSound::FLOAT) + st = new TSoundTrackStereo32Float(sampleRate, channelCount, sampleCount); + break; + } + + if (!st) { std::string s; s = "Type " + std::to_string(sampleRate) + " Hz " + std::to_string(bitPerSample) + " bits "; @@ -134,20 +152,21 @@ TSoundTrackP TSoundTrack::create(TUINT32 sampleRate, int bitPerSample, TSoundTrackP TSoundTrack::create(TUINT32 sampleRate, int bitPerSample, int channelCount, TINT32 sampleCount, - void *buffer, bool signedSample) { + int sampleType, void *buffer) { TSoundTrackP st; int type = bitPerSample + channelCount; switch (type) { case TRK_M8: - if (signedSample) + if (sampleType == TSound::INT) st = new TSoundTrackMono8Signed(sampleRate, channelCount, sampleCount, (TMono8SignedSample *)buffer, 0); - else + else if (sampleType == TSound::UINT) st = new TSoundTrackMono8Unsigned(sampleRate, channelCount, sampleCount, (TMono8UnsignedSample *)buffer, 0); break; + case TRK_S8: - if (signedSample) + if (sampleType == TSound::INT) st = new TSoundTrackStereo8Signed(sampleRate, channelCount, sampleCount, (TStereo8SignedSample *)buffer, 0); else @@ -156,26 +175,43 @@ TSoundTrackP TSoundTrack::create(TUINT32 sampleRate, int bitPerSample, break; case TRK_M16: - st = new TSoundTrackMono16(sampleRate, channelCount, sampleCount, - (TMono16Sample *)buffer, 0); + if (sampleType == TSound::INT) + st = new TSoundTrackMono16(sampleRate, channelCount, sampleCount, + (TMono16Sample *)buffer, 0); break; case TRK_S16: - st = new TSoundTrackStereo16(sampleRate, channelCount, sampleCount, - (TStereo16Sample *)buffer, 0); + if (sampleType == TSound::INT) + st = new TSoundTrackStereo16(sampleRate, channelCount, sampleCount, + (TStereo16Sample *)buffer, 0); break; case TRK_M24: - st = new TSoundTrackMono24(sampleRate, channelCount, sampleCount, - (TMono24Sample *)buffer, 0); + if (sampleType == TSound::INT) + st = new TSoundTrackMono24(sampleRate, channelCount, sampleCount, + (TMono24Sample *)buffer, 0); break; case TRK_S24: - st = new TSoundTrackStereo24(sampleRate, channelCount, sampleCount, - (TStereo24Sample *)buffer, 0); + if (sampleType == TSound::INT) + st = new TSoundTrackStereo24(sampleRate, channelCount, sampleCount, + (TStereo24Sample *)buffer, 0); + break; + + case TRK_M32: + if (sampleType == TSound::FLOAT) + st = new TSoundTrackMono32Float(sampleRate, channelCount, sampleCount, + (TMono32FloatSample *)buffer, 0); break; - default: + case TRK_S32: + if (sampleType == TSound::FLOAT) + st = new TSoundTrackStereo32Float(sampleRate, channelCount, sampleCount, + (TStereo32FloatSample *)buffer, 0); + break; + } + + if (!st) { std::string s; s = "Type " + std::to_string(sampleRate) + " Hz " + std::to_string(bitPerSample) + " bits "; @@ -196,8 +232,8 @@ TSoundTrackP TSoundTrack::create(TUINT32 sampleRate, int bitPerSample, TSoundTrackP TSoundTrack::create(const TSoundTrackFormat &format, TINT32 sampleCount, void *buffer) { return TSoundTrack::create((int)format.m_sampleRate, format.m_bitPerSample, - format.m_channelCount, sampleCount, buffer, - format.m_signedSample); + format.m_channelCount, sampleCount, + format.m_sampleType, buffer); } //------------------------------------------------------------------------------ @@ -206,7 +242,7 @@ TSoundTrackP TSoundTrack::create(const TSoundTrackFormat &format, TINT32 sampleCount) { return TSoundTrack::create((int)format.m_sampleRate, format.m_bitPerSample, format.m_channelCount, sampleCount, - format.m_signedSample); + format.m_sampleType); } //------------------------------------------------------------------------------ @@ -230,7 +266,7 @@ bool TSoundTrackFormat::operator==(const TSoundTrackFormat &rhs) { return (m_sampleRate == rhs.m_sampleRate && m_bitPerSample == rhs.m_bitPerSample && m_channelCount == rhs.m_channelCount && - m_signedSample == rhs.m_signedSample); + m_sampleType == rhs.m_sampleType); } //------------------------------------------------------------------------------ @@ -249,7 +285,7 @@ double TSoundTrack::getDuration() const { TSoundTrackFormat TSoundTrack::getFormat() const { return TSoundTrackFormat(getSampleRate(), getBitPerSample(), - getChannelCount(), isSampleSigned()); + getChannelCount(), getSampleType()); } //------------------------------------------------------------------------------ diff --git a/toonz/sources/common/tsound/tsound_nt.cpp b/toonz/sources/common/tsound/tsound_nt.cpp index 89554bb..bf8f37f 100644 --- a/toonz/sources/common/tsound/tsound_nt.cpp +++ b/toonz/sources/common/tsound/tsound_nt.cpp @@ -39,7 +39,7 @@ MMRESULT getControlDetails(HMIXEROBJ hMixer, DWORD dwSelectControlID, MIXERCONTROLDETAILS_UNSIGNED *mxcdSelectValue); MMRESULT isaFormatSupported(int sampleRate, int channelCount, int bitPerSample, - bool input); + int sampleType, bool input); DWORD WINAPI MyWaveOutCallbackThread(LPVOID lpParameter); void getAmplitude(int &litude, const TSoundTrackP st, TINT32 sample); @@ -490,7 +490,7 @@ TSoundOutputDeviceImp::~TSoundOutputDeviceImp() { delete m_whdrQueue; } bool TSoundOutputDeviceImp::doOpenDevice(const TSoundTrackFormat &format) { WAVEFORMATEX wf; - wf.wFormatTag = WAVE_FORMAT_PCM; + wf.wFormatTag = format.m_sampleType & TSound::WMASK; wf.nChannels = format.m_channelCount; wf.nSamplesPerSec = format.m_sampleRate; wf.wBitsPerSample = format.m_bitPerSample; @@ -560,6 +560,8 @@ void TSoundOutputDeviceImp::insertAllRate() { m_supportedRate.insert(32000); m_supportedRate.insert(44100); m_supportedRate.insert(48000); + m_supportedRate.insert(96000); + m_supportedRate.insert(192000); } //---------------------------------------------------------------------------- @@ -817,15 +819,20 @@ TSoundTrackFormat TSoundOutputDevice::getPreferredFormat(TUINT32 sampleRate, } else sampleRate = *it; - if (bitPerSample <= 8) + // Normalize bit sample and set preferred sample type + if (bitPerSample <= 8) { bitPerSample = 8; - else if ((bitPerSample > 8 && bitPerSample < 16) || bitPerSample >= 16) + fmt.m_sampleType = TSound::UINT; + } else if (bitPerSample <= 16) { bitPerSample = 16; - - if (bitPerSample >= 16) - fmt.m_signedSample = true; - else - fmt.m_signedSample = false; + fmt.m_sampleType = TSound::INT; + } else if (bitPerSample <= 24) { + bitPerSample = 24; + fmt.m_sampleType = TSound::INT; + } else if (bitPerSample <= 32) { + bitPerSample = 32; + fmt.m_sampleType = TSound::FLOAT; + } // switch mono/stereo if (channelCount <= 1) @@ -865,14 +872,14 @@ class WaveFormat final : public WAVEFORMATEX { public: WaveFormat(){}; WaveFormat(unsigned char channelCount, TUINT32 sampleRate, - unsigned char bitPerSample); + unsigned char bitPerSample, int sampleFormat); ~WaveFormat(){}; }; WaveFormat::WaveFormat(unsigned char channelCount, TUINT32 sampleRate, - unsigned char bitPerSample) { - wFormatTag = WAVE_FORMAT_PCM; + unsigned char bitPerSample, int sampleFormat) { + wFormatTag = sampleFormat & TSound::WMASK; nChannels = channelCount; nSamplesPerSec = sampleRate; wBitsPerSample = bitPerSample; @@ -1102,6 +1109,8 @@ void TSoundInputDeviceImp::insertAllRate() { m_supportedRate.insert(32000); m_supportedRate.insert(44100); m_supportedRate.insert(48000); + m_supportedRate.insert(96000); + m_supportedRate.insert(192000); } //---------------------------------------------------------------------------- @@ -1213,7 +1222,7 @@ throw TException("This format is not supported for recording");*/ try { WaveFormat wf(m_imp->m_format.m_channelCount, m_imp->m_format.m_sampleRate, - m_imp->m_format.m_bitPerSample); + m_imp->m_format.m_bitPerSample, m_imp->m_format.m_sampleType); m_imp->open(wf); } catch (TException &e) { @@ -1285,7 +1294,7 @@ throw TException("This format is not supported for recording");*/ m_imp->m_byteRecorded = 0; try { WaveFormat wf(m_imp->m_format.m_channelCount, m_imp->m_format.m_sampleRate, - m_imp->m_format.m_bitPerSample); + m_imp->m_format.m_bitPerSample, m_imp->m_format.m_sampleType); m_imp->open(wf); m_imp->prepareHeader( @@ -1713,15 +1722,20 @@ TSoundTrackFormat TSoundInputDevice::getPreferredFormat(TUINT32 sampleRate, } else sampleRate = *it; - if (bitPerSample <= 8) - bitPerSample = 8; - else if ((bitPerSample > 8 && bitPerSample < 16) || bitPerSample >= 16) - bitPerSample = 16; - - if (bitPerSample >= 16) - fmt.m_signedSample = true; - else - fmt.m_signedSample = false; + // Normalize bit sample and set preferred sample type + if (bitPerSample <= 8) { + bitPerSample = 8; + fmt.m_sampleType = TSound::UINT; + } else if (bitPerSample <= 16) { + bitPerSample = 16; + fmt.m_sampleType = TSound::INT; + } else if (bitPerSample <= 24) { + bitPerSample = 24; + fmt.m_sampleType = TSound::INT; + } else if (bitPerSample <= 32) { + bitPerSample = 32; + fmt.m_sampleType = TSound::FLOAT; + } // switch mono/stereo if (channelCount <= 1) @@ -2156,11 +2170,11 @@ bool setRecordLine(TSoundInputDevice::Source typeInput) { //------------------------------------------------------------------------------ MMRESULT isaFormatSupported(int sampleRate, int channelCount, int bitPerSample, - bool input) { + int sampleType, bool input) { WAVEFORMATEX wf; MMRESULT ret; - wf.wFormatTag = WAVE_FORMAT_PCM; + wf.wFormatTag = sampleType & TSound::WMASK; wf.nChannels = channelCount; wf.nSamplesPerSec = sampleRate; wf.wBitsPerSample = bitPerSample; diff --git a/toonz/sources/common/tsound/tsound_qt.cpp b/toonz/sources/common/tsound/tsound_qt.cpp index a0187e3..fef761c 100644 --- a/toonz/sources/common/tsound/tsound_qt.cpp +++ b/toonz/sources/common/tsound/tsound_qt.cpp @@ -157,9 +157,14 @@ public: format.setCodec("audio/pcm"); format.setChannelCount(st->getChannelCount()); format.setByteOrder(QAudioFormat::LittleEndian); - format.setSampleType( st->getFormat().m_signedSample - ? QAudioFormat::SignedInt - : QAudioFormat::UnSignedInt ); + switch (st->getSampleType()) { + case TSound::INT: + format.setSampleType(QAudioFormat::SignedInt); + case TSound::UINT: + format.setSampleType(QAudioFormat::UnSignedInt); + case TSound::FLOAT: + format.setSampleType(QAudioFormat::Float); + } format.setSampleRate(st->getSampleRate()); QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); diff --git a/toonz/sources/image/3gp/tiio_3gp_proxy.cpp b/toonz/sources/image/3gp/tiio_3gp_proxy.cpp index 1902418..99a353b 100644 --- a/toonz/sources/image/3gp/tiio_3gp_proxy.cpp +++ b/toonz/sources/image/3gp/tiio_3gp_proxy.cpp @@ -226,7 +226,7 @@ void TLevelWriter3gp::saveSoundTrack(TSoundTrack *st) { stream << (msg << QString("$LW3gpSaveSoundTrack") << m_id << st->getSampleRate() << st->getBitPerSample() << st->getChannelCount() << st->getSampleCount() - << st->getFormat().m_signedSample); + << (st->getFormat().m_sampleType != TSound::UINT)); t32bitsrv::BufferExchanger exch((UCHAR *)st->getRawData()); tipc::writeShMemBuffer(stream, msg << tipc::clr, size, &exch); diff --git a/toonz/sources/image/mov/tiio_mov_proxy.cpp b/toonz/sources/image/mov/tiio_mov_proxy.cpp index 2622aa4..619111d 100644 --- a/toonz/sources/image/mov/tiio_mov_proxy.cpp +++ b/toonz/sources/image/mov/tiio_mov_proxy.cpp @@ -294,7 +294,7 @@ void TLevelWriterMov::saveSoundTrack(TSoundTrack *st) { stream << (msg << QString("$LWMovSaveSoundTrack") << m_id << st->getSampleRate() << st->getBitPerSample() << st->getChannelCount() << st->getSampleCount() - << st->getFormat().m_signedSample); + << (st->getFormat().m_sampleType != TSound::UINT)); t32bitsrv::BufferExchanger exch((UCHAR *)st->getRawData()); tipc::writeShMemBuffer(stream, msg << tipc::clr, size, &exch); diff --git a/toonz/sources/include/tsound.h b/toonz/sources/include/tsound.h index 2d76aea..aac5884 100644 --- a/toonz/sources/include/tsound.h +++ b/toonz/sources/include/tsound.h @@ -27,7 +27,12 @@ typedef UCHAR Channel; const int MONO = 0; const int LEFT = 0; const int RIGHT = LEFT + 1; -} + +const int WMASK = 7; // Mask for wFormat +const int INT = 1; // WAVE_FORMAT_PCM +const int UINT = 9; // WAVE_FORMAT_PCM (Unsigned 8-Bits) +const int FLOAT = 3; // WAVE_FORMAT_IEEE_FLOAT +} // namespace TSound //========================================================= @@ -52,14 +57,14 @@ public: TUINT32 m_sampleRate; // frequenza di campionamento int m_bitPerSample; // numero di bit per campione int m_channelCount; // numero di canali - bool m_signedSample; + int m_sampleType; // integer or float samples TSoundTrackFormat(TUINT32 sampleRate = 0, int bitPerSample = 0, - int channelCount = 0, bool signedSample = true) + int channelCount = 0, int sampleType = TSound::INT) : m_sampleRate(sampleRate) , m_bitPerSample(bitPerSample) , m_channelCount(channelCount) - , m_signedSample(signedSample) {} + , m_sampleType(sampleType) {} ~TSoundTrackFormat() {} @@ -84,6 +89,7 @@ protected: int m_bitPerSample; // numero di bit per campione TINT32 m_sampleCount; // numero di campioni int m_channelCount; // numero di canali + int m_sampleType; // integer or float samples TSoundTrack *m_parent; // nel caso di sotto-traccie @@ -93,10 +99,10 @@ protected: TSoundTrack(); TSoundTrack(TUINT32 sampleRate, int bitPerSample, int channelCount, - int sampleSize, TINT32 sampleCount, bool isSampleSigned); + int sampleSize, TINT32 sampleCount, int sampleType); TSoundTrack(TUINT32 sampleRate, int bitPerSample, int channelCount, - int sampleSize, TINT32 sampleCount, UCHAR *buffer, + int sampleSize, TINT32 sampleCount, int sampleType, UCHAR *buffer, TSoundTrack *parent); public: @@ -107,11 +113,11 @@ signedSample must be true for tracks whose samples are signed */ static TSoundTrackP create(TUINT32 sampleRate, int bitPerSample, int channelCount, TINT32 sampleCount, - bool signedSample = true); + int sampleFormat); static TSoundTrackP create(TUINT32 sampleRate, int bitPerSample, - int channelCount, TINT32 sampleCount, void *buffer, - bool signedSample = true); + int channelCount, TINT32 sampleCount, + int sampleFormat, void *buffer); /*! Create a new soundtrack according to the format and number of samples @@ -143,6 +149,9 @@ specified as inputs //! Returns true if the samples of the soundtrack are signed, false otherwise virtual bool isSampleSigned() const = 0; + //! Returns sample format + virtual int getSampleType() const = 0; + //! Returns the soundtrack format TSoundTrackFormat getFormat() const; diff --git a/toonz/sources/include/tsound_t.h b/toonz/sources/include/tsound_t.h index 42b99bd..e615b78 100644 --- a/toonz/sources/include/tsound_t.h +++ b/toonz/sources/include/tsound_t.h @@ -26,7 +26,7 @@ public: TSoundTrackT(TUINT32 sampleRate, int channelCount, TINT32 sampleCount) : TSoundTrack(sampleRate, T::getBitPerSample(), channelCount, sizeof(T), - sampleCount, T::isSampleSigned()) {} + sampleCount, T::getSampleType()) {} //---------------------------------------------------------------------------- @@ -34,7 +34,8 @@ public: T *buffer, TSoundTrackT *parent) : TSoundTrack(sampleRate, T::getBitPerSample(), channelCount, sizeof(T), - sampleCount, reinterpret_cast(buffer), parent) {} + sampleCount, T::getSampleType(), + reinterpret_cast(buffer), parent) {} //---------------------------------------------------------------------------- @@ -42,7 +43,13 @@ public: //---------------------------------------------------------------------------- - bool isSampleSigned() const override { return T::isSampleSigned(); } + bool isSampleSigned() const override { + return T::getSampleType() != TSound::UINT; + } + + //---------------------------------------------------------------------------- + + int getSampleType() const override { return T::getSampleType(); } //---------------------------------------------------------------------------- @@ -351,6 +358,8 @@ template class DVAPI TSoundTrackT; template class DVAPI TSoundTrackT; template class DVAPI TSoundTrackT; template class DVAPI TSoundTrackT; +template class DVAPI TSoundTrackT; +template class DVAPI TSoundTrackT; #endif typedef TSoundTrackT TSoundTrackMono8Signed; @@ -361,6 +370,8 @@ typedef TSoundTrackT TSoundTrackMono16; typedef TSoundTrackT TSoundTrackStereo16; typedef TSoundTrackT TSoundTrackMono24; typedef TSoundTrackT TSoundTrackStereo24; +typedef TSoundTrackT TSoundTrackMono32Float; +typedef TSoundTrackT TSoundTrackStereo32Float; //============================================================================== @@ -379,6 +390,8 @@ public: virtual TSoundTrackP compute(const TSoundTrackStereo16 &) { return 0; }; virtual TSoundTrackP compute(const TSoundTrackMono24 &) { return 0; }; virtual TSoundTrackP compute(const TSoundTrackStereo24 &) { return 0; }; + virtual TSoundTrackP compute(const TSoundTrackMono32Float &) { return 0; }; + virtual TSoundTrackP compute(const TSoundTrackStereo32Float &) { return 0; }; }; //============================================================================== diff --git a/toonz/sources/include/tsoundsample.h b/toonz/sources/include/tsoundsample.h index f5bf992..d97ccad 100644 --- a/toonz/sources/include/tsoundsample.h +++ b/toonz/sources/include/tsoundsample.h @@ -24,6 +24,8 @@ class TMono16Sample; class TStereo16Sample; class TMono24Sample; class TStereo24Sample; +class TMono32FloatSample; +class TStereo32FloatSample; //============================================================================== @@ -39,6 +41,7 @@ public: static bool isSampleSigned() { return true; } static int getBitPerSample() { return 8; } + static int getSampleType() { return TSound::INT; } inline SCHAR getValue(TSound::Channel /*chan*/) const { return value; } @@ -76,6 +79,8 @@ public: static inline TMono8SignedSample from(const TStereo16Sample &sample); static inline TMono8SignedSample from(const TMono24Sample &sample); static inline TMono8SignedSample from(const TStereo24Sample &sample); + static inline TMono8SignedSample from(const TMono32FloatSample &sample); + static inline TMono8SignedSample from(const TStereo32FloatSample &sample); }; inline TMono8SignedSample operator+(const TMono8SignedSample &s1, @@ -98,6 +103,7 @@ public: static bool isSampleSigned() { return false; } static int getBitPerSample() { return 8; } + static int getSampleType() { return TSound::UINT; } inline UCHAR getValue(TSound::Channel /*chan*/) const { return value; } @@ -136,6 +142,8 @@ public: static inline TMono8UnsignedSample from(const TStereo16Sample &sample); static inline TMono8UnsignedSample from(const TMono24Sample &sample); static inline TMono8UnsignedSample from(const TStereo24Sample &sample); + static inline TMono8UnsignedSample from(const TMono32FloatSample &sample); + static inline TMono8UnsignedSample from(const TStereo32FloatSample &sample); }; inline TMono8UnsignedSample operator+(const TMono8UnsignedSample &s1, @@ -167,6 +175,7 @@ public: static bool isSampleSigned() { return true; } static int getBitPerSample() { return 8; } + static int getSampleType() { return TSound::INT; } inline SCHAR getValue(TSound::Channel chan) const { assert(chan <= 1); @@ -217,6 +226,8 @@ public: static inline TStereo8SignedSample from(const TStereo16Sample &sample); static inline TStereo8SignedSample from(const TMono24Sample &sample); static inline TStereo8SignedSample from(const TStereo24Sample &sample); + static inline TStereo8SignedSample from(const TMono32FloatSample &sample); + static inline TStereo8SignedSample from(const TStereo32FloatSample &sample); }; inline TStereo8SignedSample operator+(const TStereo8SignedSample &s1, @@ -248,6 +259,7 @@ public: static bool isSampleSigned() { return false; } static int getBitPerSample() { return 8; } + static int getSampleType() { return TSound::UINT; } inline UCHAR getValue(TSound::Channel chan) const { assert(chan <= 1); @@ -303,6 +315,8 @@ public: static inline TStereo8UnsignedSample from(const TStereo16Sample &sample); static inline TStereo8UnsignedSample from(const TMono24Sample &sample); static inline TStereo8UnsignedSample from(const TStereo24Sample &sample); + static inline TStereo8UnsignedSample from(const TMono32FloatSample &sample); + static inline TStereo8UnsignedSample from(const TStereo32FloatSample &sample); }; inline TStereo8UnsignedSample operator+(const TStereo8UnsignedSample &s1, @@ -325,6 +339,7 @@ public: static bool isSampleSigned() { return true; } static int getBitPerSample() { return 16; } + static int getSampleType() { return TSound::INT; } inline short getValue(TSound::Channel) const { return value; } @@ -362,6 +377,8 @@ public: static inline TMono16Sample from(const TStereo16Sample &sample); static inline TMono16Sample from(const TMono24Sample &sample); static inline TMono16Sample from(const TStereo24Sample &sample); + static inline TMono16Sample from(const TMono32FloatSample &sample); + static inline TMono16Sample from(const TStereo32FloatSample &sample); }; inline TMono16Sample operator+(const TMono16Sample &s1, @@ -393,6 +410,7 @@ public: static bool isSampleSigned() { return true; } static int getBitPerSample() { return 16; } + static int getSampleType() { return TSound::INT; } inline short getValue(TSound::Channel chan) const { assert(chan <= 1); @@ -443,6 +461,8 @@ public: static inline TStereo16Sample from(const TStereo16Sample &sample); static inline TStereo16Sample from(const TMono24Sample &sample); static inline TStereo16Sample from(const TStereo24Sample &sample); + static inline TStereo16Sample from(const TMono32FloatSample &sample); + static inline TStereo16Sample from(const TStereo32FloatSample &sample); }; inline TStereo16Sample operator+(const TStereo16Sample &s1, @@ -454,22 +474,29 @@ inline TStereo16Sample operator+(const TStereo16Sample &s1, //========================================================= class DVAPI TMono24Sample { - TINT32 value; + UCHAR byte[3]; // LSB first public: typedef TINT32 ChannelValueType; typedef TMono24Sample ChannelSampleType; - TMono24Sample(TINT32 v = 0) : value(tcrop(v, -8388608, 8388607)) {} + TMono24Sample(TINT32 v = 0) { setValue(0, v); } ~TMono24Sample(){}; static bool isSampleSigned() { return true; } static int getBitPerSample() { return 24; } + static int getSampleType() { return TSound::INT; } - inline TINT32 getValue(TSound::Channel) const { return value; } + inline TINT32 getValue(TSound::Channel) const { + return byte[0] | (byte[1] << 8) | (byte[2] << 16) | + (byte[2] & 0x80 ? ~0xFFFFFF : 0); + } inline void setValue(TSound::Channel /*chan*/, TINT32 v) { - value = tcrop(v, -8388608, 8388607); + int iVal = tcrop(v, -8388608, 8388607); + byte[0] = iVal; + byte[1] = iVal >> 8; + byte[2] = iVal >> 16; } inline double getPressure(TSound::Channel chan) const { @@ -477,14 +504,12 @@ public: } inline TMono24Sample &operator+=(const TMono24Sample &s) { - int iVal = value + s.value; - value = tcrop(iVal, -8388608, 8388607); + setValue(0, getValue(0) + s.getValue(0)); return *this; } inline TMono24Sample &operator*=(double a) { - int iVal = (int)(value * a); - value = tcrop(iVal, -8388608, 8388607); + setValue(0, getValue(0) * a); return *this; } @@ -492,8 +517,8 @@ public: static TMono24Sample mix(const TMono24Sample &s1, double a1, const TMono24Sample &s2, double a2) { - return TMono24Sample( - tcrop((int)(s1.value * a1 + s2.value * a2), -8388608, 8388607)); + int iVal = s1.getValue(0) * a1 + s2.getValue(0) * a2; + return TMono24Sample(iVal); } static inline TMono24Sample from(const TMono8UnsignedSample &sample); @@ -504,6 +529,8 @@ public: static inline TMono24Sample from(const TStereo16Sample &sample); static inline TMono24Sample from(const TMono24Sample &sample); static inline TMono24Sample from(const TStereo24Sample &sample); + static inline TMono24Sample from(const TMono32FloatSample &sample); + static inline TMono24Sample from(const TStereo32FloatSample &sample); }; inline TMono24Sample operator+(const TMono24Sample &s1, @@ -515,30 +542,40 @@ inline TMono24Sample operator+(const TMono24Sample &s1, //========================================================= class DVAPI TStereo24Sample { - TINT32 channel[2]; // l'ordine dei canali e' left,right + typedef struct { + UCHAR byte[3]; // LSB first + } TSample; + TSample channel[2]; // l'ordine dei canali e' left,right public: typedef TINT32 ChannelValueType; typedef TMono24Sample ChannelSampleType; TStereo24Sample(TINT32 lchan = 0, TINT32 rchan = 0) { - channel[0] = tcrop(lchan, -8388608, 8388607); - channel[1] = tcrop(rchan, -8388608, 8388607); + setValue(0, lchan); + setValue(1, rchan); } ~TStereo24Sample(){}; static bool isSampleSigned() { return true; } static int getBitPerSample() { return 24; } + static int getSampleType() { return TSound::INT; } inline TINT32 getValue(TSound::Channel chan) const { assert(chan <= 1); - return channel[chan]; + const TSample &s = channel[chan]; + return s.byte[0] | (s.byte[1] << 8) | (s.byte[2] << 16) | + (s.byte[2] & 0x80 ? ~0xFFFFFF : 0); } inline void setValue(TSound::Channel chan, TINT32 v) { assert(chan <= 1); - channel[chan] = tcrop(v, -8388608, 8388607); + int iVal = tcrop(v, -8388608, 8388607); + TSample &s = channel[chan]; + s.byte[0] = iVal; + s.byte[1] = iVal >> 8; + s.byte[2] = iVal >> 16; } inline double getPressure(TSound::Channel chan) const { @@ -546,18 +583,14 @@ public: } inline TStereo24Sample &operator+=(const TStereo24Sample &s) { - int iLeftVal = channel[0] + s.channel[0]; - int iRightVal = channel[1] + s.channel[1]; - channel[0] = tcrop(iLeftVal, -8388608, 8388607); - channel[1] = tcrop(iRightVal, -8388608, 8388607); + setValue(0, getValue(0) + s.getValue(0)); + setValue(1, getValue(1) + s.getValue(1)); return *this; } inline TStereo24Sample &operator*=(double a) { - int iLeftVal = (int)(a * channel[0]); - int iRightVal = (int)(a * channel[1]); - channel[0] = tcrop(iLeftVal, -8388608, 8388607); - channel[1] = tcrop(iRightVal, -8388608, 8388607); + setValue(0, getValue(0) * a); + setValue(1, getValue(1) * a); return *this; } @@ -567,10 +600,9 @@ public: static TStereo24Sample mix(const TStereo24Sample &s1, double a1, const TStereo24Sample &s2, double a2) { - return TStereo24Sample(tcrop((int)(s1.channel[0] * a1 + s2.channel[0] * a2), - -8388608, 8388607), - tcrop((int)(s1.channel[1] * a1 + s2.channel[1] * a2), - -8388608, 8388607)); + int iValL = s1.getValue(0) * a1 + s2.getValue(0) * a2; + int iValR = s1.getValue(1) * a1 + s2.getValue(1) * a2; + return TStereo24Sample(iValL, iValR); } static inline TStereo24Sample from(const TMono8UnsignedSample &sample); @@ -581,6 +613,8 @@ public: static inline TStereo24Sample from(const TStereo16Sample &sample); static inline TStereo24Sample from(const TMono24Sample &sample); static inline TStereo24Sample from(const TStereo24Sample &sample); + static inline TStereo24Sample from(const TMono32FloatSample &sample); + static inline TStereo24Sample from(const TStereo32FloatSample &sample); }; inline TStereo24Sample operator+(const TStereo24Sample &s1, @@ -589,6 +623,141 @@ inline TStereo24Sample operator+(const TStereo24Sample &s1, return s += s2; } +//========================================================= + +class DVAPI TMono32FloatSample { + float value; + +public: + typedef float ChannelValueType; + typedef TMono32FloatSample ChannelSampleType; + + TMono32FloatSample(float v = 0.0f) : value(v) {} + ~TMono32FloatSample(){}; + + static bool isSampleSigned() { return true; } + static int getBitPerSample() { return 32; } + static int getSampleType() { return TSound::FLOAT; } + + inline float getValue(TSound::Channel) const { return value; } + + inline void setValue(TSound::Channel /*chan*/, float v) { + value = v; + } + + inline double getPressure(TSound::Channel chan) const { + return (getValue(chan)); + } + + inline TMono32FloatSample &operator+=(const TMono32FloatSample &s) { + value += s.value; + return *this; + } + + inline TMono32FloatSample &operator*=(double a) { + value *= a; + return *this; + } + + inline TMono32FloatSample operator*(double a) { return TMono32FloatSample(*this) *= a; } + + static TMono32FloatSample mix(const TMono32FloatSample &s1, double a1, + const TMono32FloatSample &s2, double a2) { + return TMono32FloatSample(s1.value * a1 + s2.value * a2); + } + + static inline TMono32FloatSample from(const TMono8UnsignedSample &sample); + static inline TMono32FloatSample from(const TMono8SignedSample &sample); + static inline TMono32FloatSample from(const TStereo8SignedSample &sample); + static inline TMono32FloatSample from(const TStereo8UnsignedSample &sample); + static inline TMono32FloatSample from(const TMono16Sample &sample); + static inline TMono32FloatSample from(const TStereo16Sample &sample); + static inline TMono32FloatSample from(const TMono24Sample &sample); + static inline TMono32FloatSample from(const TStereo24Sample &sample); + static inline TMono32FloatSample from(const TMono32FloatSample &sample); + static inline TMono32FloatSample from(const TStereo32FloatSample &sample); +}; + +inline TMono32FloatSample operator+(const TMono32FloatSample &s1, + const TMono32FloatSample &s2) { + TMono32FloatSample s = s1; + return s += s2; +} + +//========================================================= + +class DVAPI TStereo32FloatSample { + float channel[2]; // l'ordine dei canali e' left,right + +public: + typedef float ChannelValueType; + typedef TMono32FloatSample ChannelSampleType; + + TStereo32FloatSample(float lchan = 0.0f, float rchan = 0.0f) { + channel[0] = lchan; + channel[1] = rchan; + } + + ~TStereo32FloatSample(){}; + + static bool isSampleSigned() { return true; } + static int getBitPerSample() { return 32; } + static int getSampleType() { return TSound::FLOAT; } + + inline float getValue(TSound::Channel chan) const { + assert(chan <= 1); + return channel[chan]; + } + + inline void setValue(TSound::Channel chan, float v) { + assert(chan <= 1); + channel[chan] = v; + } + + inline double getPressure(TSound::Channel chan) const { + return (getValue(chan)); + } + + inline TStereo32FloatSample &operator+=(const TStereo32FloatSample &s) { + channel[0] += s.channel[0]; + channel[1] += s.channel[1]; + return *this; + } + + inline TStereo32FloatSample &operator*=(double a) { + channel[0] *= a; + channel[1] *= a; + return *this; + } + + inline TStereo32FloatSample operator*(double a) { + return TStereo32FloatSample(*this) *= a; + } + + static TStereo32FloatSample mix(const TStereo32FloatSample &s1, double a1, + const TStereo32FloatSample &s2, double a2) { + return TStereo32FloatSample(s1.channel[0] * a1 + s2.channel[0] * a2, + s1.channel[1] * a1 + s2.channel[1] * a2); + } + + static inline TStereo32FloatSample from(const TMono8UnsignedSample &sample); + static inline TStereo32FloatSample from(const TMono8SignedSample &sample); + static inline TStereo32FloatSample from(const TStereo8SignedSample &sample); + static inline TStereo32FloatSample from(const TStereo8UnsignedSample &sample); + static inline TStereo32FloatSample from(const TMono16Sample &sample); + static inline TStereo32FloatSample from(const TStereo16Sample &sample); + static inline TStereo32FloatSample from(const TMono24Sample &sample); + static inline TStereo32FloatSample from(const TStereo24Sample &sample); + static inline TStereo32FloatSample from(const TMono32FloatSample &sample); + static inline TStereo32FloatSample from(const TStereo32FloatSample &sample); +}; + +inline TStereo32FloatSample operator+(const TStereo32FloatSample &s1, + const TStereo32FloatSample &s2) { + TStereo32FloatSample s = s1; + return s += s2; +} + //============================================================================== inline TMono8SignedSample TMono8SignedSample::from( @@ -600,7 +769,7 @@ inline TMono8SignedSample TMono8SignedSample::from( inline TMono8SignedSample TMono8SignedSample::from( const TMono8UnsignedSample &sample) { - return TMono8SignedSample(sample.getValue(TSound::LEFT) - 128); + return TMono8SignedSample(sample.getValue(TSound::MONO) - 128); } //------------------------------------------------------------------------------ @@ -624,7 +793,7 @@ inline TMono8SignedSample TMono8SignedSample::from( inline TMono8SignedSample TMono8SignedSample::from( const TMono16Sample &sample) { - int val = (sample.getValue(TSound::LEFT) >> 8); + int val = (sample.getValue(TSound::MONO) >> 8); return TMono8SignedSample(val); } @@ -640,7 +809,7 @@ inline TMono8SignedSample TMono8SignedSample::from( inline TMono8SignedSample TMono8SignedSample::from( const TMono24Sample &sample) { - int val = (sample.getValue(TSound::LEFT) >> 16); + int val = (sample.getValue(TSound::MONO) >> 16); return TMono8SignedSample(val); } @@ -653,11 +822,28 @@ inline TMono8SignedSample TMono8SignedSample::from( return TMono8SignedSample(val); } +//------------------------------------------------------------------------------ + +inline TMono8SignedSample TMono8SignedSample::from( + const TMono32FloatSample &sample) { + float fval = sample.getValue(TSound::MONO) * 128.0; + return TMono8SignedSample(tcrop((int)fval, -128, 127)); +} + +//------------------------------------------------------------------------------ + +inline TMono8SignedSample TMono8SignedSample::from( + const TStereo32FloatSample &sample) { + float fval = + (sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT)) * 64.0; + return TMono8SignedSample(tcrop((int)fval, -128, 127)); +} + //============================================================================== inline TMono8UnsignedSample TMono8UnsignedSample::from( const TMono8SignedSample &sample) { - return TMono8UnsignedSample(sample.getValue(TSound::LEFT) + 128); + return TMono8UnsignedSample(sample.getValue(TSound::MONO) + 128); } //------------------------------------------------------------------------------ @@ -718,11 +904,28 @@ inline TMono8UnsignedSample TMono8UnsignedSample::from( 128); } +//------------------------------------------------------------------------------ + +inline TMono8UnsignedSample TMono8UnsignedSample::from( + const TMono32FloatSample &sample) { + float fval = sample.getValue(TSound::MONO) * 128.0; + return TMono8UnsignedSample(tcrop((int)fval + 128, 0, 255)); +} + +//------------------------------------------------------------------------------ + +inline TMono8UnsignedSample TMono8UnsignedSample::from( + const TStereo32FloatSample &sample) { + float fval = + (sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT)) * 64.0; + return TMono8UnsignedSample(tcrop((int)fval + 128, 0, 255)); +} + //============================================================================== inline TStereo8SignedSample TStereo8SignedSample::from( const TMono8UnsignedSample &sample) { - int srcval = sample.getValue(TSound::LEFT) - 128; + int srcval = sample.getValue(TSound::MONO) - 128; return TStereo8SignedSample(srcval, srcval); } @@ -730,7 +933,7 @@ inline TStereo8SignedSample TStereo8SignedSample::from( inline TStereo8SignedSample TStereo8SignedSample::from( const TMono8SignedSample &sample) { - int srcval = sample.getValue(TSound::LEFT); + int srcval = sample.getValue(TSound::MONO); return TStereo8SignedSample(srcval, srcval); } @@ -745,17 +948,16 @@ inline TStereo8SignedSample TStereo8SignedSample::from( inline TStereo8SignedSample TStereo8SignedSample::from( const TStereo8UnsignedSample &sample) { - int srcval = - ((sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT)) >> 1) - - 128; - return TStereo8SignedSample(srcval, srcval); + int srcvalL = sample.getValue(TSound::LEFT) - 128; + int srcvalR = sample.getValue(TSound::RIGHT) - 128; + return TStereo8SignedSample(srcvalL, srcvalR); } //------------------------------------------------------------------------------ inline TStereo8SignedSample TStereo8SignedSample::from( const TMono16Sample &sample) { - int srcval = sample.getValue(TSound::LEFT) >> 8; + int srcval = sample.getValue(TSound::MONO) >> 8; return TStereo8SignedSample(srcval, srcval); } @@ -763,16 +965,16 @@ inline TStereo8SignedSample TStereo8SignedSample::from( inline TStereo8SignedSample TStereo8SignedSample::from( const TStereo16Sample &sample) { - int srcval = - (sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT)) >> 9; - return TStereo8SignedSample(srcval, srcval); + int srcvalL = sample.getValue(TSound::LEFT) >> 8; + int srcvalR = sample.getValue(TSound::RIGHT) >> 8; + return TStereo8SignedSample(srcvalL, srcvalR); } //------------------------------------------------------------------------------ inline TStereo8SignedSample TStereo8SignedSample::from( const TMono24Sample &sample) { - int srcval = sample.getValue(TSound::LEFT) >> 16; + int srcval = sample.getValue(TSound::MONO) >> 16; return TStereo8SignedSample(srcval, srcval); } @@ -780,16 +982,35 @@ inline TStereo8SignedSample TStereo8SignedSample::from( inline TStereo8SignedSample TStereo8SignedSample::from( const TStereo24Sample &sample) { - int srcval = - (sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT)) >> 17; + int srcvalL = sample.getValue(TSound::LEFT) >> 16; + int srcvalR = sample.getValue(TSound::RIGHT) >> 16; + return TStereo8SignedSample(srcvalL, srcvalR); +} + +//------------------------------------------------------------------------------ + +inline TStereo8SignedSample TStereo8SignedSample::from( + const TMono32FloatSample &sample) { + float fval = sample.getValue(TSound::MONO) * 128.0; + int srcval = tcrop((int)fval, -128, 127); return TStereo8SignedSample(srcval, srcval); } +//------------------------------------------------------------------------------ + +inline TStereo8SignedSample TStereo8SignedSample::from( + const TStereo32FloatSample &sample) { + float fvalL = sample.getValue(TSound::LEFT) * 128.0; + float fvalR = sample.getValue(TSound::RIGHT) * 128.0; + return TStereo8SignedSample(tcrop((int)fvalL, -128, 127), + tcrop((int)fvalR, -128, 127)); +} + //============================================================================== inline TStereo8UnsignedSample TStereo8UnsignedSample::from( const TMono8UnsignedSample &sample) { - int srcval = sample.getValue(TSound::LEFT); + int srcval = sample.getValue(TSound::MONO); return TStereo8UnsignedSample(srcval, srcval); } @@ -798,7 +1019,7 @@ inline TStereo8UnsignedSample TStereo8UnsignedSample::from( inline TStereo8UnsignedSample TStereo8UnsignedSample::from( const TMono8SignedSample &sample) { - int srcval = sample.getValue(TSound::LEFT) + 128; + int srcval = sample.getValue(TSound::MONO) + 128; return TStereo8UnsignedSample(srcval, srcval); } @@ -814,17 +1035,16 @@ inline TStereo8UnsignedSample TStereo8UnsignedSample::from( inline TStereo8UnsignedSample TStereo8UnsignedSample::from( const TStereo8SignedSample &sample) { - int srcval = - ((sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT)) >> 1) + - 128; - return TStereo8UnsignedSample(srcval, srcval); + int srcvalL = sample.getValue(TSound::LEFT) + 128; + int srcvalR = sample.getValue(TSound::RIGHT) + 128; + return TStereo8UnsignedSample(srcvalL, srcvalR); } //------------------------------------------------------------------------------ inline TStereo8UnsignedSample TStereo8UnsignedSample::from( const TMono16Sample &sample) { - int srcval = (sample.getValue(TSound::LEFT) >> 8) + 128; + int srcval = (sample.getValue(TSound::MONO) >> 8) + 128; return TStereo8UnsignedSample(srcval, srcval); } @@ -832,17 +1052,16 @@ inline TStereo8UnsignedSample TStereo8UnsignedSample::from( inline TStereo8UnsignedSample TStereo8UnsignedSample::from( const TStereo16Sample &sample) { - int srcval = - ((sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT)) >> 9) + - 128; - return TStereo8UnsignedSample(srcval, srcval); + int srcvalL = (sample.getValue(TSound::LEFT) >> 8) + 128; + int srcvalR = (sample.getValue(TSound::RIGHT) >> 8) + 128; + return TStereo8UnsignedSample(srcvalL, srcvalR); } //------------------------------------------------------------------------------ inline TStereo8UnsignedSample TStereo8UnsignedSample::from( const TMono24Sample &sample) { - int srcval = (sample.getValue(TSound::LEFT) >> 16) + 128; + int srcval = (sample.getValue(TSound::MONO) >> 16) + 128; return TStereo8UnsignedSample(srcval, srcval); } @@ -850,22 +1069,40 @@ inline TStereo8UnsignedSample TStereo8UnsignedSample::from( inline TStereo8UnsignedSample TStereo8UnsignedSample::from( const TStereo24Sample &sample) { - int srcval = - ((sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT)) >> 17) + - 128; + int srcvalL = (sample.getValue(TSound::LEFT) >> 16) + 128; + int srcvalR = (sample.getValue(TSound::RIGHT) >> 16) + 128; + return TStereo8UnsignedSample(srcvalL, srcvalR); +} + +//------------------------------------------------------------------------------ + +inline TStereo8UnsignedSample TStereo8UnsignedSample::from( + const TMono32FloatSample &sample) { + float fval = sample.getValue(TSound::MONO) * 128.0; + int srcval = tcrop((int)fval + 128, 0, 255); return TStereo8UnsignedSample(srcval, srcval); } +//------------------------------------------------------------------------------ + +inline TStereo8UnsignedSample TStereo8UnsignedSample::from( + const TStereo32FloatSample &sample) { + float fvalL = sample.getValue(TSound::LEFT) * 128.0; + float fvalR = sample.getValue(TSound::RIGHT) * 128.0; + return TStereo8UnsignedSample(tcrop((int)fvalL + 128, 0, 255), + tcrop((int)fvalR + 128, 0, 255)); +} + //============================================================================== inline TMono16Sample TMono16Sample::from(const TMono8UnsignedSample &sample) { - return TMono16Sample((sample.getValue(TSound::LEFT) - 128) << 8); + return TMono16Sample((sample.getValue(TSound::MONO) - 128) << 8); } //------------------------------------------------------------------------------ inline TMono16Sample TMono16Sample::from(const TMono8SignedSample &sample) { - return TMono16Sample(sample.getValue(TSound::LEFT) << 8); + return TMono16Sample(sample.getValue(TSound::MONO) << 8); } //------------------------------------------------------------------------------ @@ -899,7 +1136,7 @@ inline TMono16Sample TMono16Sample::from(const TStereo16Sample &sample) { //------------------------------------------------------------------------------ inline TMono16Sample TMono16Sample::from(const TMono24Sample &sample) { - int srcval = (sample.getValue(TSound::LEFT) >> 8); + int srcval = (sample.getValue(TSound::MONO) >> 8); return TMono16Sample(srcval); } @@ -911,18 +1148,34 @@ inline TMono16Sample TMono16Sample::from(const TStereo24Sample &sample) { return TMono16Sample(srcval); } +//------------------------------------------------------------------------------ + +inline TMono16Sample TMono16Sample::from(const TMono32FloatSample &sample) { + float fval = sample.getValue(TSound::MONO) * 32768.0; + return TMono16Sample(tcrop((int)fval, -32768, 32767)); +} + +//------------------------------------------------------------------------------ + +inline TMono16Sample TMono16Sample::from(const TStereo32FloatSample &sample) { + float fval = + (sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT)) * + 16384.0; + return TMono16Sample(tcrop((int)fval, -32768, 32767)); +} + //============================================================================== inline TStereo16Sample TStereo16Sample::from( const TMono8UnsignedSample &sample) { - int srcval = (sample.getValue(TSound::LEFT) - 128) << 8; + int srcval = (sample.getValue(TSound::MONO) - 128) << 8; return TStereo16Sample(srcval, srcval); } //------------------------------------------------------------------------------ inline TStereo16Sample TStereo16Sample::from(const TMono8SignedSample &sample) { - int srcval = sample.getValue(TSound::LEFT) << 8; + int srcval = sample.getValue(TSound::MONO) << 8; return TStereo16Sample(srcval, srcval); } @@ -930,25 +1183,24 @@ inline TStereo16Sample TStereo16Sample::from(const TMono8SignedSample &sample) { inline TStereo16Sample TStereo16Sample::from( const TStereo8SignedSample &sample) { - int srcval = (sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT)) - << 7; - return TStereo16Sample(srcval, srcval); + int srcvalL = sample.getValue(TSound::LEFT) << 8; + int srcvalR = sample.getValue(TSound::RIGHT) << 8; + return TStereo16Sample(srcvalL, srcvalR); } //------------------------------------------------------------------------------ inline TStereo16Sample TStereo16Sample::from( const TStereo8UnsignedSample &sample) { - int srcval = - (sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT) - 256) - << 7; - return TStereo16Sample(srcval, srcval); + int srcvalL = (sample.getValue(TSound::LEFT) - 128) << 8; + int srcvalR = (sample.getValue(TSound::RIGHT) - 128) << 8; + return TStereo16Sample(srcvalL, srcvalR); } //------------------------------------------------------------------------------ inline TStereo16Sample TStereo16Sample::from(const TMono16Sample &sample) { - int srcval = sample.getValue(TSound::LEFT); + int srcval = sample.getValue(TSound::MONO); return TStereo16Sample(srcval, srcval); } @@ -961,29 +1213,46 @@ inline TStereo16Sample TStereo16Sample::from(const TStereo16Sample &sample) { //------------------------------------------------------------------------------ inline TStereo16Sample TStereo16Sample::from(const TMono24Sample &sample) { - int srcval = (sample.getValue(TSound::LEFT) >> 8); + int srcval = (sample.getValue(TSound::MONO) >> 8); return TStereo16Sample(srcval, srcval); } //------------------------------------------------------------------------------ inline TStereo16Sample TStereo16Sample::from(const TStereo24Sample &sample) { - int srcval = - ((sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT)) >> 9); + int srcvalL = sample.getValue(TSound::LEFT) >> 8; + int srcvalR = sample.getValue(TSound::RIGHT) >> 8; + return TStereo16Sample(srcvalL, srcvalR); +} + +//------------------------------------------------------------------------------ + +inline TStereo16Sample TStereo16Sample::from(const TMono32FloatSample &sample) { + float fval = sample.getValue(TSound::MONO) * 32768.0; + int srcval = tcrop((int)fval, -32768, 32767); return TStereo16Sample(srcval, srcval); } +//------------------------------------------------------------------------------ + +inline TStereo16Sample TStereo16Sample::from(const TStereo32FloatSample &sample) { + float fvalL = sample.getValue(TSound::LEFT) * 32768.0; + float fvalR = sample.getValue(TSound::RIGHT) * 32768.0; + return TStereo16Sample(tcrop((int)fvalL, -32768, 32767), + tcrop((int)fvalR, -32768, 32767)); +} + //============================================================================== inline TMono24Sample TMono24Sample::from(const TMono8UnsignedSample &sample) { - int srcval = (sample.getValue(TSound::LEFT) - 128) << 16; + int srcval = (sample.getValue(TSound::MONO) - 128) << 16; return TMono24Sample(srcval); } //------------------------------------------------------------------------------ inline TMono24Sample TMono24Sample::from(const TMono8SignedSample &sample) { - int srcval = sample.getValue(TSound::LEFT) << 16; + int srcval = sample.getValue(TSound::MONO) << 16; return TMono24Sample(srcval); } @@ -1007,7 +1276,7 @@ inline TMono24Sample TMono24Sample::from(const TStereo8UnsignedSample &sample) { //------------------------------------------------------------------------------ inline TMono24Sample TMono24Sample::from(const TMono16Sample &sample) { - int srcval = sample.getValue(TSound::LEFT) << 8; + int srcval = sample.getValue(TSound::MONO) << 8; return TMono24Sample(srcval); } @@ -1033,18 +1302,34 @@ inline TMono24Sample TMono24Sample::from(const TStereo24Sample &sample) { return TMono24Sample(srcval); } +//------------------------------------------------------------------------------ + +inline TMono24Sample TMono24Sample::from(const TMono32FloatSample &sample) { + float fval = sample.getValue(TSound::MONO) * 8388608.0; + return TMono24Sample(tcrop((int)fval, -8388608, 8388607)); +} + +//------------------------------------------------------------------------------ + +inline TMono24Sample TMono24Sample::from(const TStereo32FloatSample &sample) { + float fval = + (sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT)) * + 4194304.0; + return TMono24Sample(tcrop((int)fval, -8388608, 8388607)); +} + //============================================================================== inline TStereo24Sample TStereo24Sample::from( const TMono8UnsignedSample &sample) { - int srcval = (sample.getValue(TSound::LEFT) - 128) << 16; + int srcval = (sample.getValue(TSound::MONO) - 128) << 16; return TStereo24Sample(srcval, srcval); } //------------------------------------------------------------------------------ inline TStereo24Sample TStereo24Sample::from(const TMono8SignedSample &sample) { - int srcval = sample.getValue(TSound::LEFT) << 16; + int srcval = sample.getValue(TSound::MONO) << 16; return TStereo24Sample(srcval, srcval); } @@ -1052,40 +1337,39 @@ inline TStereo24Sample TStereo24Sample::from(const TMono8SignedSample &sample) { inline TStereo24Sample TStereo24Sample::from( const TStereo8SignedSample &sample) { - int srcval = (sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT)) - << 15; - return TStereo24Sample(srcval, srcval); + int srcvalL = sample.getValue(TSound::LEFT) << 16; + int srcvalR = sample.getValue(TSound::RIGHT) << 16; + return TStereo24Sample(srcvalL, srcvalR); } //------------------------------------------------------------------------------ inline TStereo24Sample TStereo24Sample::from( const TStereo8UnsignedSample &sample) { - int srcval = - (sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT) - 256) - << 15; - return TStereo24Sample(srcval, srcval); + int srcvalL = (sample.getValue(TSound::LEFT) - 128) << 16; + int srcvalR = (sample.getValue(TSound::RIGHT) - 128) << 16; + return TStereo24Sample(srcvalL, srcvalR); } //------------------------------------------------------------------------------ inline TStereo24Sample TStereo24Sample::from(const TMono16Sample &sample) { - int srcval = sample.getValue(TSound::LEFT) << 8; + int srcval = sample.getValue(TSound::MONO) << 8; return TStereo24Sample(srcval, srcval); } //------------------------------------------------------------------------------ inline TStereo24Sample TStereo24Sample::from(const TStereo16Sample &sample) { - int srcval = (sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT)) - << 7; - return TStereo24Sample(srcval, srcval); + int srcvalL = sample.getValue(TSound::LEFT) << 8; + int srcvalR = sample.getValue(TSound::RIGHT) << 8; + return TStereo24Sample(srcvalL, srcvalR); } //------------------------------------------------------------------------------ inline TStereo24Sample TStereo24Sample::from(const TMono24Sample &sample) { - int srcval = sample.getValue(TSound::LEFT); + int srcval = sample.getValue(TSound::MONO); return TStereo24Sample(srcval, srcval); } @@ -1095,4 +1379,174 @@ inline TStereo24Sample TStereo24Sample::from(const TStereo24Sample &sample) { return sample; } +//------------------------------------------------------------------------------ + +inline TStereo24Sample TStereo24Sample::from(const TMono32FloatSample &sample) { + float fval = sample.getValue(TSound::MONO) * 8388608.0; + int srcval = tcrop((int)fval, -8388608, 8388607); + return TStereo24Sample(srcval, srcval); +} + +//------------------------------------------------------------------------------ + +inline TStereo24Sample TStereo24Sample::from(const TStereo32FloatSample &sample) { + float fvalL = sample.getValue(TSound::LEFT) * 8388608.0; + float fvalR = sample.getValue(TSound::RIGHT) * 8388608.0; + return TStereo24Sample(tcrop((int)fvalL, -8388608, 8388607), + tcrop((int)fvalR, -8388608, 8388607)); +} + +//============================================================================== + +inline TMono32FloatSample TMono32FloatSample::from(const TMono8UnsignedSample &sample) { + float srcval = (sample.getValue(TSound::MONO) - 128) / 128.0; + return TMono32FloatSample(srcval); +} + +//------------------------------------------------------------------------------ + +inline TMono32FloatSample TMono32FloatSample::from(const TMono8SignedSample &sample) { + float srcval = sample.getValue(TSound::MONO) / 128.0; + return TMono32FloatSample(srcval); +} + +//------------------------------------------------------------------------------ + +inline TMono32FloatSample TMono32FloatSample::from(const TStereo8SignedSample &sample) { + float srcval = + (sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT)) / 256.0; + return TMono32FloatSample(srcval); +} + +//------------------------------------------------------------------------------ + +inline TMono32FloatSample TMono32FloatSample::from(const TStereo8UnsignedSample &sample) { + float srcval = + (sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT) - 256) / + 256.0; + return TMono32FloatSample(srcval); +} + +//------------------------------------------------------------------------------ + +inline TMono32FloatSample TMono32FloatSample::from(const TMono16Sample &sample) { + float srcval = sample.getValue(TSound::MONO) / 32768.0; + return TMono32FloatSample(srcval); +} + +//------------------------------------------------------------------------------ + +inline TMono32FloatSample TMono32FloatSample::from(const TStereo16Sample &sample) { + float srcval = + (sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT)) / + 65536.0; + return TMono32FloatSample(srcval); +} + +//------------------------------------------------------------------------------ + +inline TMono32FloatSample TMono32FloatSample::from(const TMono24Sample &sample) { + float srcval = sample.getValue(TSound::MONO) / 8388608.0; + return TMono32FloatSample(srcval); +} + +//------------------------------------------------------------------------------ + +inline TMono32FloatSample TMono32FloatSample::from(const TStereo24Sample &sample) { + float srcval = + (sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT)) / + 16777216.0; + return TMono32FloatSample(srcval); +} + +//------------------------------------------------------------------------------ + +inline TMono32FloatSample TMono32FloatSample::from(const TMono32FloatSample &sample) { + return sample; +} + +//------------------------------------------------------------------------------ + +inline TMono32FloatSample TMono32FloatSample::from(const TStereo32FloatSample &sample) { + float srcval = + (sample.getValue(TSound::LEFT) + sample.getValue(TSound::RIGHT)) / 2.0; + return TMono32FloatSample(srcval); +} + +//============================================================================== + +inline TStereo32FloatSample TStereo32FloatSample::from( + const TMono8UnsignedSample &sample) { + float srcval = (sample.getValue(TSound::MONO) - 128) / 128.0; + return TStereo32FloatSample(srcval, srcval); +} + +//------------------------------------------------------------------------------ + +inline TStereo32FloatSample TStereo32FloatSample::from(const TMono8SignedSample &sample) { + float srcval = sample.getValue(TSound::MONO) / 128.0; + return TStereo32FloatSample(srcval, srcval); +} + +//------------------------------------------------------------------------------ + +inline TStereo32FloatSample TStereo32FloatSample::from( + const TStereo8SignedSample &sample) { + float srcvalL = sample.getValue(TSound::LEFT) / 128.0; + float srcvalR = sample.getValue(TSound::RIGHT) / 128.0; + return TStereo32FloatSample(srcvalL, srcvalR); +} + +//------------------------------------------------------------------------------ + +inline TStereo32FloatSample TStereo32FloatSample::from( + const TStereo8UnsignedSample &sample) { + float srcvalL = (sample.getValue(TSound::LEFT) - 128) / 128.0; + float srcvalR = (sample.getValue(TSound::RIGHT) - 128) / 128.0; + return TStereo32FloatSample(srcvalL, srcvalR); +} + +//------------------------------------------------------------------------------ + +inline TStereo32FloatSample TStereo32FloatSample::from(const TMono16Sample &sample) { + float srcval = sample.getValue(TSound::MONO) / 32768.0; + return TStereo32FloatSample(srcval, srcval); +} + +//------------------------------------------------------------------------------ + +inline TStereo32FloatSample TStereo32FloatSample::from(const TStereo16Sample &sample) { + float srcvalL = sample.getValue(TSound::LEFT) / 32768.0; + float srcvalR = sample.getValue(TSound::RIGHT) / 32768.0; + return TStereo32FloatSample(srcvalL, srcvalR); +} + +//------------------------------------------------------------------------------ + +inline TStereo32FloatSample TStereo32FloatSample::from(const TMono24Sample &sample) { + float srcval = sample.getValue(TSound::MONO) / 8388608.0; + return TStereo32FloatSample(srcval, srcval); +} + +//------------------------------------------------------------------------------ + +inline TStereo32FloatSample TStereo32FloatSample::from(const TStereo24Sample &sample) { + float srcvalL = sample.getValue(TSound::LEFT) / 8388608.0; + float srcvalR = sample.getValue(TSound::RIGHT) / 8388608.0; + return TStereo32FloatSample(srcvalL, srcvalR); +} + +//------------------------------------------------------------------------------ + +inline TStereo32FloatSample TStereo32FloatSample::from(const TMono32FloatSample &sample) { + float srcval = sample.getValue(TSound::MONO); + return TStereo32FloatSample(srcval, srcval); +} + +//------------------------------------------------------------------------------ + +inline TStereo32FloatSample TStereo32FloatSample::from(const TStereo32FloatSample &sample) { + return sample; +} + #endif diff --git a/toonz/sources/sound/aiff/tsio_aiff.cpp b/toonz/sources/sound/aiff/tsio_aiff.cpp index b27f122..3ccd2fd 100644 --- a/toonz/sources/sound/aiff/tsio_aiff.cpp +++ b/toonz/sources/sound/aiff/tsio_aiff.cpp @@ -78,6 +78,7 @@ public: TCOMMChunk(string name, TINT32 length) : TAIFFChunk(name, length) {} bool read(ifstream &is) override { + long pos = is.tellg(); is.read((char *)&m_chans, sizeof(m_chans)); is.read((char *)&m_frames, sizeof(m_frames)); is.read((char *)&m_bitPerSample, sizeof(m_bitPerSample)); @@ -92,6 +93,7 @@ public: memset(sampleRateBuffer, 0, 10); is.read((char *)&sampleRateBuffer, sizeof(sampleRateBuffer)); m_sampleRate = convertToLong(sampleRateBuffer); + is.seekg(pos + (long)m_length, is.beg); return true; } @@ -311,7 +313,7 @@ TSoundTrackP TSoundTrackReaderAiff::load() { formType[4] = '\0'; // il formType DEVE essere uguale a "AIFF" - if ((string(formType, 4) != "AIFF")) + if ((string(formType, 4) != "AIFF") && (string(formType, 4) != "AIFC")) throw TException("The AIFF file doesn't contain the AIFF form"); TCOMMChunk *commChunk = 0; @@ -388,7 +390,7 @@ TSoundTrackP TSoundTrackReaderAiff::load() { (void *)(ssndChunk->m_waveData.get() + ssndChunk->m_offset), commChunk->m_frames * track->getSampleSize()); else - swapAndCopySamples( + swapAndCopy16Bits( (short *)(ssndChunk->m_waveData.get() + ssndChunk->m_offset), (short *)track->getRawData(), (TINT32)(commChunk->m_frames * commChunk->m_chans)); @@ -402,44 +404,34 @@ TSoundTrackP TSoundTrackReaderAiff::load() { track = new TSoundTrackStereo24(commChunk->m_sampleRate, 2, (TINT32)commChunk->m_frames); - if (!TNZ_LITTLE_ENDIAN) { - UCHAR *begin = (UCHAR *)track->getRawData(); - for (int i = 0; i < (int)(commChunk->m_frames * commChunk->m_chans); - ++i) { // dovrebbe andare bene anche adesso - *(begin + 4 * i) = 0; - *(begin + 4 * i + 1) = - *(ssndChunk->m_waveData.get() + ssndChunk->m_offset + 3 * i); - *(begin + 4 * i + 2) = - *(ssndChunk->m_waveData.get() + ssndChunk->m_offset + 3 * i + 1); - *(begin + 4 * i + 3) = - *(ssndChunk->m_waveData.get() + ssndChunk->m_offset + 3 * i + 2); - } - } else { - UCHAR *begin = (UCHAR *)track->getRawData(); - for (int i = 0; i < (int)(commChunk->m_frames * commChunk->m_chans); - ++i) { - *(begin + 4 * i) = - *(ssndChunk->m_waveData.get() + ssndChunk->m_offset + 3 * i + 2); - *(begin + 4 * i + 1) = - *(ssndChunk->m_waveData.get() + ssndChunk->m_offset + 3 * i + 1); - *(begin + 4 * i + 2) = - *(ssndChunk->m_waveData.get() + ssndChunk->m_offset + 3 * i); - *(begin + 4 * i + 3) = 0; - - /* -*(begin + 4*i) = 0; -*(begin + 4*i + 3) = -*(ssndChunk->m_waveData+ssndChunk->m_offset + 3*i + 2); - -// sono i due byte che vengono invertiti -*(begin + 4*i + 1) = -*(ssndChunk->m_waveData+ssndChunk->m_offset + 3*i + 1); -*(begin + 4*i + 2) = -*(ssndChunk->m_waveData+ssndChunk->m_offset + 3*i); -*/ - } - } - break; + if (!TNZ_LITTLE_ENDIAN) + memcpy((void *)track->getRawData(), + (void *)(ssndChunk->m_waveData.get() + ssndChunk->m_offset), + commChunk->m_frames * track->getSampleSize()); + else + swapAndCopy24Bits( + (void *)(ssndChunk->m_waveData.get() + ssndChunk->m_offset), + (void *)track->getRawData(), + (TINT32)(commChunk->m_frames * commChunk->m_chans)); + break; + case 32: + if (commChunk->m_chans == 1) + track = new TSoundTrackMono32Float(commChunk->m_sampleRate, 1, + (TINT32)commChunk->m_frames); + else // due canali + track = new TSoundTrackStereo32Float(commChunk->m_sampleRate, 2, + (TINT32)commChunk->m_frames); + + if (!TNZ_LITTLE_ENDIAN) + memcpy((void *)track->getRawData(), + (void *)(ssndChunk->m_waveData.get() + ssndChunk->m_offset), + commChunk->m_frames * track->getSampleSize()); + else + swapAndCopy32Bits( + (TINT32 *)(ssndChunk->m_waveData.get() + ssndChunk->m_offset), + (TINT32 *)track->getRawData(), + (TINT32)(commChunk->m_frames * commChunk->m_chans)); + break; } if (commChunk) delete commChunk; @@ -498,40 +490,29 @@ bool TSoundTrackWriterAiff::save(const TSoundTrackP &st) { if (TNZ_LITTLE_ENDIAN) { postHeadData = swapTINT32(postHeadData); - if (commChunk.m_bitPerSample == 16) { - swapAndCopySamples((short *)sndtrack->getRawData(), - (short *)waveData.get(), - (TINT32)(commChunk.m_frames * commChunk.m_chans)); - } else if (commChunk.m_bitPerSample == 24) { - UCHAR *begin = (UCHAR *)sndtrack->getRawData(); - for (int i = 0; i < (int)commChunk.m_frames * commChunk.m_chans; ++i) { - *(waveData.get() + 3 * i) = *(begin + 4 * i + 2); - *(waveData.get() + 3 * i + 1) = *(begin + 4 * i + 1); - *(waveData.get() + 3 * i + 2) = *(begin + 4 * i); - - /* -*(waveData + 3*i + 2) = *(begin + 4*i + 3); - -// posiziona in modo corretto i due byte prima invertiti -*(waveData + 3*i) = *(begin + 4*i + 2); -*(waveData + 3*i + 1) = *(begin + 4*i + 1); -*/ - } - } else - memcpy((void *)waveData.get(), (void *)sndtrack->getRawData(), - soundDataCount); - } else { - if (commChunk.m_bitPerSample != 24) + switch (commChunk.m_bitPerSample) { + case 16: + swapAndCopy16Bits((short *)sndtrack->getRawData(), + (short *)waveData.get(), + (TINT32)(commChunk.m_frames * commChunk.m_chans)); + break; + case 24: + swapAndCopy24Bits((void *)sndtrack->getRawData(), (void *)waveData.get(), + (TINT32)(commChunk.m_frames * commChunk.m_chans)); + break; + case 32: + swapAndCopy32Bits((TINT32 *)sndtrack->getRawData(), + (TINT32 *)waveData.get(), + (TINT32)(commChunk.m_frames * commChunk.m_chans)); + break; + default: memcpy((void *)waveData.get(), (void *)sndtrack->getRawData(), soundDataCount); - else { - UCHAR *begin = (UCHAR *)sndtrack->getRawData(); - for (int i = 0; i < (int)commChunk.m_frames * commChunk.m_chans; ++i) { - *(waveData.get() + 3 * i) = *(begin + 4 * i + 1); - *(waveData.get() + 3 * i + 1) = *(begin + 4 * i + 2); - *(waveData.get() + 3 * i + 2) = *(begin + 4 * i + 3); - } + break; } + } else { + memcpy((void *)waveData.get(), (void *)sndtrack->getRawData(), + soundDataCount); } ssndChunk.m_waveData = std::move(waveData); diff --git a/toonz/sources/sound/tsio.cpp b/toonz/sources/sound/tsio.cpp index 9c48f8a..0625e6d 100644 --- a/toonz/sources/sound/tsio.cpp +++ b/toonz/sources/sound/tsio.cpp @@ -29,6 +29,13 @@ void initSoundIo() { TSoundTrackReader::define("mp3", TSoundTrackReaderMp3::create); // TSoundTrackWriter::define("mp3", TSoundTrackWriterMp3::create); TFileType::declare("mp3", TFileType::AUDIO_LEVEL); + + // TSoundTrackReaderMp3 is so generic that will work for other ffmpeg + // audio formats, nice :D + TSoundTrackReader::define("ogg", TSoundTrackReaderMp3::create); + TFileType::declare("ogg", TFileType::AUDIO_LEVEL); + TSoundTrackReader::define("flac", TSoundTrackReaderMp3::create); + TFileType::declare("flac", TFileType::AUDIO_LEVEL); } // return &info; } diff --git a/toonz/sources/sound/tsioutils.cpp b/toonz/sources/sound/tsioutils.cpp index b7c6b3d..b775a76 100644 --- a/toonz/sources/sound/tsioutils.cpp +++ b/toonz/sources/sound/tsioutils.cpp @@ -5,11 +5,36 @@ #include "tsioutils.h" //------------------------------------------------------------------------------ -void swapAndCopySamples(short *srcBuffer, short *dstBuffer, +void swapAndCopy16Bits(const short *srcBuffer, short *dstBuffer, TINT32 sampleCount) { - short *srcSample = srcBuffer; + const short *srcSample = srcBuffer; short *dstSample = dstBuffer; - short *endSrcSample = srcSample + sampleCount; + const short *endSrcSample = srcSample + sampleCount; while (srcSample < endSrcSample) *dstSample++ = swapShort(*srcSample++); } + +//------------------------------------------------------------------------------ +void swapAndCopy32Bits(const TINT32 *srcBuffer, TINT32 *dstBuffer, + TINT32 sampleCount) { + const TINT32 *srcSample = srcBuffer; + TINT32 *dstSample = dstBuffer; + + const TINT32 *endSrcSample = srcSample + sampleCount; + while (srcSample < endSrcSample) *dstSample++ = swapTINT32(*srcSample++); +} + +//------------------------------------------------------------------------------ +void swapAndCopy24Bits(const void *srcBuffer, void *dstBuffer, + TINT32 sampleCount) { + const UCHAR *srcData = (const UCHAR *)srcBuffer; + UCHAR *dstData = (UCHAR *)dstBuffer; + if (sampleCount <= 0) return; + while (--sampleCount) { + dstData[0] = srcData[2]; + dstData[1] = srcData[1]; + dstData[2] = srcData[0]; + srcData += 3; + dstData += 3; + } +} diff --git a/toonz/sources/sound/tsioutils.h b/toonz/sources/sound/tsioutils.h index abf75c0..054f394 100644 --- a/toonz/sources/sound/tsioutils.h +++ b/toonz/sources/sound/tsioutils.h @@ -3,6 +3,13 @@ #ifndef TSIOUTILS_INCLUDED #define TSIOUTILS_INCLUDED -void swapAndCopySamples(short *srcBuffer, short *dstBuffer, TINT32 sampleCount); +void swapAndCopy16Bits(const short *srcBuffer, short *dstBuffer, + TINT32 sampleCount); + +void swapAndCopy32Bits(const TINT32 *srcBuffer, TINT32 *dstBuffer, + TINT32 sampleCount); + +void swapAndCopy24Bits(const void *srcBuffer, void *dstBuffer, + TINT32 sampleCount); #endif diff --git a/toonz/sources/sound/wav/tsio_wav.cpp b/toonz/sources/sound/wav/tsio_wav.cpp index 4b15960..e356732 100644 --- a/toonz/sources/sound/wav/tsio_wav.cpp +++ b/toonz/sources/sound/wav/tsio_wav.cpp @@ -4,6 +4,7 @@ #include "tsio_wav.h" #include "tsystem.h" #include "tfilepath_io.h" +#include "tsioutils.h" using namespace std; @@ -11,11 +12,6 @@ using namespace std; TNZ_LITTLE_ENDIAN undefined !! #endif - //------------------------------------------------------------------------------ - - void - swapAndCopySamples(short *srcBuffer, short *dstBuffer, TINT32 sampleCount); - //============================================================================== // TWAVChunk: classe base per i vari chunk WAV @@ -247,73 +243,48 @@ TSoundTrackP TSoundTrackReaderWav::load() { if (fmtChunk && dataChunk) { TINT32 sampleCount = dataChunk->m_length / fmtChunk->m_bytesPerSample; - bool signedSample = (fmtChunk->m_bitPerSample != 8); + int sampleType = 0; + + if (fmtChunk->m_encodingType == 1) // WAVE_FORMAT_PCM + sampleType = (fmtChunk->m_bitPerSample == 8) ? TSound::UINT : TSound::INT; + else if (fmtChunk->m_encodingType == 3) // WAVE_FORMAT_IEEE_FLOAT + sampleType = TSound::FLOAT; - track = TSoundTrack::create((int)fmtChunk->m_sampleRate, - fmtChunk->m_bitPerSample, fmtChunk->m_chans, - sampleCount, signedSample); + if (sampleType) // valid sample type + track = TSoundTrack::create((int)fmtChunk->m_sampleRate, + fmtChunk->m_bitPerSample, fmtChunk->m_chans, + sampleCount, sampleType); if (track) { - switch (fmtChunk->m_bitPerSample) { - case 8: - memcpy((void *)track->getRawData(), - (void *)(dataChunk->m_samples.get()), - sampleCount * fmtChunk->m_bytesPerSample); - break; - case 16: - if (!TNZ_LITTLE_ENDIAN) - swapAndCopySamples((short *)dataChunk->m_samples.get(), - (short *)track->getRawData(), - sampleCount * fmtChunk->m_chans); - else + if (!TNZ_LITTLE_ENDIAN) { + switch (fmtChunk->m_bitPerSample) { + case 16: + swapAndCopy16Bits((short *)dataChunk->m_samples.get(), + (short *)track->getRawData(), + sampleCount * fmtChunk->m_chans); + break; + case 24: + swapAndCopy24Bits((short *)dataChunk->m_samples.get(), + (short *)track->getRawData(), + sampleCount * fmtChunk->m_chans); + break; + case 32: + swapAndCopy32Bits((TINT32 *)dataChunk->m_samples.get(), + (TINT32 *)track->getRawData(), + sampleCount * fmtChunk->m_chans); + break; + default: memcpy((void *)track->getRawData(), (void *)(dataChunk->m_samples.get()), sampleCount * fmtChunk->m_bytesPerSample); - //#endif - break; - case 24: - if (!TNZ_LITTLE_ENDIAN) { - UCHAR *begin = (UCHAR *)track->getRawData(); - for (int i = 0; i < (int)(sampleCount * fmtChunk->m_chans); ++i) { - *(begin + 4 * i) = 0; - *(begin + 4 * i + 1) = *(dataChunk->m_samples.get() + 3 * i + 2); - *(begin + 4 * i + 2) = *(dataChunk->m_samples.get() + 3 * i + 1); - *(begin + 4 * i + 3) = *(dataChunk->m_samples.get() + 3 * i); - } - } else { - UCHAR *begin = (UCHAR *)track->getRawData(); - for (int i = 0; i < (int)(sampleCount * fmtChunk->m_chans); ++i) { - memcpy((void *)(begin + 4 * i), - (void *)(dataChunk->m_samples.get() + 3 * i), 3); - *(begin + 4 * i + 3) = 0; - } + break; } - //#endif - break; + } else { + memcpy((void *)track->getRawData(), + (void *)(dataChunk->m_samples.get()), + sampleCount * fmtChunk->m_bytesPerSample); } } - - /*if (!TNZ_LITTLE_ENDIAN) -{ -if (fmtChunk->m_bitPerSample > 8) -{ -assert(fmtChunk->m_bitPerSample <= 16); -swapAndCopySamples( -(short*)dataChunk->m_samples, -(short*)track->getRawData(), -sampleCount*fmtChunk->m_chans); -} -else -memcpy( - (void*)track->getRawData(), -(void*)(dataChunk->m_samples), -sampleCount*fmtChunk->m_bytesPerSample); -} -else -memcpy( -(void*)track->getRawData(), -(void*)(dataChunk->m_samples), -sampleCount*fmtChunk->m_bytesPerSample);*/ } if (fmtChunk) delete fmtChunk; @@ -353,7 +324,7 @@ bool TSoundTrackWriterWav::save(const TSoundTrackP &sndtrack) { TFMTChunk fmtChunk(16); - fmtChunk.m_encodingType = 1; // PCM + fmtChunk.m_encodingType = sndtrack->getSampleType() & TSound::WMASK; fmtChunk.m_chans = sndtrack->getChannelCount(); fmtChunk.m_sampleRate = sndtrack->getSampleRate(); fmtChunk.m_avgBytesPerSecond = (sndtrack->getBitPerSample() / 8) * @@ -369,40 +340,32 @@ bool TSoundTrackWriterWav::save(const TSoundTrackP &sndtrack) { if (!TNZ_LITTLE_ENDIAN) RIFFChunkLength = swapTINT32(RIFFChunkLength); -// era if defined(MACOSX) -#if (!TNZ_LITTLE_ENDIAN) - { - if (fmtChunk.m_bitPerSample == 8) - memcpy((void *)waveData.get(), (void *)sndtrack->getRawData(), soundDataLength); - else if (fmtChunk.m_bitPerSample == 16) { - swapAndCopySamples((short *)sndtrack->getRawData(), (short *)waveData.get(), - sndtrack->getSampleCount() * fmtChunk.m_chans); - } else if (fmtChunk.m_bitPerSample == 24) { // swap e togliere quarto byte - UCHAR *begin = (UCHAR *)sndtrack->getRawData(); - for (int i = 0; i < (int)sndtrack->getSampleCount() * fmtChunk.m_chans; - ++i) { - *(waveData.get() + 3 * i) = *(begin + 4 * i + 3); - *(waveData.get() + 3 * i + 1) = *(begin + 4 * i + 2); - *(waveData.get() + 3 * i + 2) = *(begin + 4 * i + 1); - } - } - } -#else - { - if (fmtChunk.m_bitPerSample != 24) + if (!TNZ_LITTLE_ENDIAN) { + switch (fmtChunk.m_bitPerSample) { + case 16: + swapAndCopy16Bits((short *)sndtrack->getRawData(), + (short *)waveData.get(), + sndtrack->getSampleCount() * fmtChunk.m_chans); + break; + case 24: + swapAndCopy24Bits((void *)sndtrack->getRawData(), (void *)waveData.get(), + sndtrack->getSampleCount() * fmtChunk.m_chans); + break; + case 32: + swapAndCopy32Bits((TINT32 *)sndtrack->getRawData(), + (TINT32 *)waveData.get(), + sndtrack->getSampleCount() * fmtChunk.m_chans); + break; + default: memcpy((void *)waveData.get(), (void *)sndtrack->getRawData(), soundDataLength); - else { // togliere quarto byte - UCHAR *begin = (UCHAR *)sndtrack->getRawData(); - for (int i = 0; i < (int)sndtrack->getSampleCount() * fmtChunk.m_chans; - ++i) { - *(waveData.get() + 3 * i) = *(begin + 4 * i); - *(waveData.get() + 3 * i + 1) = *(begin + 4 * i + 1); - *(waveData.get() + 3 * i + 2) = *(begin + 4 * i + 2); - } + break; } + } else { + memcpy((void *)waveData.get(), (void *)sndtrack->getRawData(), + soundDataLength); } -#endif + dataChunk.m_samples = std::move(waveData); os.write("RIFF", 4); diff --git a/toonz/sources/toonz/audiorecordingpopup.cpp b/toonz/sources/toonz/audiorecordingpopup.cpp index 8c8e3fd..21a5f96 100644 --- a/toonz/sources/toonz/audiorecordingpopup.cpp +++ b/toonz/sources/toonz/audiorecordingpopup.cpp @@ -51,11 +51,19 @@ #include #include +#ifndef WAVE_FORMAT_PCM +#define WAVE_FORMAT_PCM 1 +#endif +#ifndef WAVE_FORMAT_IEEE_FLOAT +#define WAVE_FORMAT_IEEE_FLOAT 3 +#endif + //============================================================================= AudioRecordingPopup::AudioRecordingPopup() : Dialog(TApp::instance()->getMainWindow(), false, true, "AudioRecording") { setWindowTitle(tr("Audio Recording")); + m_isPlaying = false; m_syncPlayback = true; m_currentFrame = 0; @@ -65,15 +73,15 @@ AudioRecordingPopup::AudioRecordingPopup() m_pauseRecordingButton = new QPushButton(this); m_pausePlaybackButton = new QPushButton(this); m_refreshDevicesButton = new QPushButton(this); - m_duration = new QLabel("00:00.000"); - m_playDuration = new QLabel("00:00.000"); - m_deviceListCB = new QComboBox(); - m_audioLevelsDisplay = new AudioLevelsDisplay(this); - m_playXSheetCB = new QCheckBox(tr("Sync with XSheet/Timeline"), this); - m_timer = new QElapsedTimer(); - m_recordedLevels = QMap(); - m_player = new QMediaPlayer(this); - m_console = FlipConsole::getCurrent(); + m_duration = new QLabel("00:00.000"); + m_playDuration = new QLabel("00:00.000"); + m_deviceListCB = new QComboBox(); + m_audioLevelsDisplay = new AudioLevelsDisplay(this); + m_playXSheetCB = new QCheckBox(tr("Sync with XSheet/Timeline"), this); + m_timer = new QElapsedTimer(); + m_recordedLevels = QMap(); + m_player = new QMediaPlayer(this); + m_console = FlipConsole::getCurrent(); m_labelDevice = new QLabel(tr("Device: ")); m_labelSamplerate = new QLabel(tr("Sample rate: ")); @@ -86,11 +94,16 @@ AudioRecordingPopup::AudioRecordingPopup() m_comboSamplerate->addItem(tr("44100 Hz"), QVariant::fromValue(44100)); m_comboSamplerate->addItem(tr("48000 Hz"), QVariant::fromValue(48000)); m_comboSamplerate->addItem(tr("96000 Hz"), QVariant::fromValue(96000)); + m_comboSamplerate->addItem(tr("192000 Hz"), QVariant::fromValue(192000)); m_comboSamplerate->setCurrentIndex(3); // 44.1KHz m_comboSamplefmt->addItem(tr("Mono 8-Bits"), QVariant::fromValue(9)); m_comboSamplefmt->addItem(tr("Stereo 8-Bits"), QVariant::fromValue(10)); m_comboSamplefmt->addItem(tr("Mono 16-Bits"), QVariant::fromValue(17)); m_comboSamplefmt->addItem(tr("Stereo 16-Bits"), QVariant::fromValue(18)); + m_comboSamplefmt->addItem(tr("Mono 24-Bits"), QVariant::fromValue(25)); + m_comboSamplefmt->addItem(tr("Stereo 24-Bits"), QVariant::fromValue(26)); + m_comboSamplefmt->addItem(tr("Mono 32-Bits"), QVariant::fromValue(33)); + m_comboSamplefmt->addItem(tr("Stereo 32-Bits"), QVariant::fromValue(34)); m_comboSamplefmt->setCurrentIndex(2); // Mono 16-Bits m_recordButton->setMaximumWidth(32); @@ -99,10 +112,10 @@ AudioRecordingPopup::AudioRecordingPopup() m_pausePlaybackButton->setMaximumWidth(32); m_refreshDevicesButton->setMaximumWidth(25); - QString playDisabled = QString(":Resources/play_disabled.svg"); - QString pauseDisabled = QString(":Resources/pause_disabled.svg"); - QString stopDisabled = QString(":Resources/stop_disabled.svg"); - QString recordDisabled = QString(":Resources/record_disabled.svg"); + QString playDisabled = QString(":Resources/play_disabled.svg"); + QString pauseDisabled = QString(":Resources/pause_disabled.svg"); + QString stopDisabled = QString(":Resources/stop_disabled.svg"); + QString recordDisabled = QString(":Resources/record_disabled.svg"); QString refreshDisabled = QString(":Resources/repeat_icon.svg"); m_pauseIcon = createQIcon("pause"); @@ -141,15 +154,21 @@ AudioRecordingPopup::AudioRecordingPopup() format = m_audioDeviceInfo.nearestFormat(format); } m_audioInput = new QAudioInput(m_audioDeviceInfo, format); + + // WAV Writter m_audioWriterWAV = new AudioWriterWAV(format); // Tool tips to provide additional info to the user m_deviceListCB->setToolTip(tr("Audio input device to record")); - m_comboSamplerate->setToolTip(tr("Number of samples per second, 44.1KHz = CD Quality")); - m_comboSamplefmt->setToolTip(tr("Number of channels and bits per sample, 16-bits recommended")); - m_playXSheetCB->setToolTip(tr("Play animation from current frame while recording/playback")); + m_comboSamplerate->setToolTip( + tr("Number of samples per second, 44.1KHz = CD Quality")); + m_comboSamplefmt->setToolTip( + tr("Number of channels and bits per sample, 16-bits recommended")); + m_playXSheetCB->setToolTip( + tr("Play animation from current frame while recording/playback")); m_saveButton->setToolTip(tr("Save recording and insert into new column")); - m_refreshDevicesButton->setToolTip(tr("Refresh list of connected audio input devices")); + m_refreshDevicesButton->setToolTip( + tr("Refresh list of connected audio input devices")); m_topLayout->setMargin(5); m_topLayout->setSpacing(8); @@ -216,28 +235,40 @@ AudioRecordingPopup::AudioRecordingPopup() m_playXSheetCB->setChecked(true); - connect(m_playXSheetCB, SIGNAL(stateChanged(int)), this, - SLOT(onPlayXSheetCBChanged(int))); - connect(m_saveButton, SIGNAL(clicked()), this, SLOT(onSaveButtonPressed())); - connect(m_recordButton, SIGNAL(clicked()), this, - SLOT(onRecordButtonPressed())); - connect(m_playButton, SIGNAL(clicked()), this, SLOT(onPlayButtonPressed())); - connect(m_pauseRecordingButton, SIGNAL(clicked()), this, - SLOT(onPauseRecordingButtonPressed())); - connect(m_pausePlaybackButton, SIGNAL(clicked()), this, - SLOT(onPausePlaybackButtonPressed())); - connect(m_audioWriterWAV, SIGNAL(update(qint64)), this, - SLOT(updateRecordDuration(qint64))); - if (m_console) connect(m_console, SIGNAL(playStateChanged(bool)), this, - SLOT(onPlayStateChanged(bool))); - connect(m_deviceListCB, SIGNAL(currentTextChanged(const QString)), this, - SLOT(onInputDeviceChanged())); - connect(m_refreshDevicesButton, SIGNAL(clicked()), this, - SLOT(onRefreshButtonPressed())); - connect(m_comboSamplerate, SIGNAL(currentTextChanged(const QString)), this, - SLOT(onAudioSettingChanged())); - connect(m_comboSamplefmt, SIGNAL(currentTextChanged(const QString)), this, - SLOT(onAudioSettingChanged())); + bool ret = connect(m_playXSheetCB, SIGNAL(stateChanged(int)), this, + SLOT(onPlayXSheetCBChanged(int))); + + ret = ret && connect(m_saveButton, SIGNAL(clicked()), this, + SLOT(onSaveButtonPressed())); + ret = ret && connect(m_recordButton, SIGNAL(clicked()), this, + SLOT(onRecordButtonPressed())); + ret = ret && connect(m_playButton, SIGNAL(clicked()), this, + SLOT(onPlayButtonPressed())); + ret = ret && connect(m_pauseRecordingButton, SIGNAL(clicked()), this, + SLOT(onPauseRecordingButtonPressed())); + ret = ret && connect(m_pausePlaybackButton, SIGNAL(clicked()), this, + SLOT(onPausePlaybackButtonPressed())); + ret = ret && connect(m_audioWriterWAV, SIGNAL(update(qint64)), this, + SLOT(updateRecordDuration(qint64))); + + if (m_console) { + ret = ret && connect(m_console, SIGNAL(playStateChanged(bool)), this, + SLOT(onPlayStateChanged(bool))); + } + + ret = + ret && connect(m_deviceListCB, SIGNAL(currentTextChanged(const QString)), + this, SLOT(onInputDeviceChanged())); + ret = ret && connect(m_refreshDevicesButton, SIGNAL(clicked()), this, + SLOT(onRefreshButtonPressed())); + ret = ret && + connect(m_comboSamplerate, SIGNAL(currentTextChanged(const QString)), + this, SLOT(onAudioSettingChanged())); + ret = ret && + connect(m_comboSamplefmt, SIGNAL(currentTextChanged(const QString)), + this, SLOT(onAudioSettingChanged())); + + assert(ret); } //----------------------------------------------------------------------------- @@ -247,12 +278,7 @@ AudioRecordingPopup::~AudioRecordingPopup() {} //----------------------------------------------------------------------------- void AudioRecordingPopup::onRecordButtonPressed() { - if (m_audioInput->state() == QAudio::InterruptedState) { - DVGui::warning( - tr("The microphone is not available: " - "\nPlease select a different device or check the microphone.")); - return; - } else if (m_audioInput->state() == QAudio::StoppedState) { + if (m_audioInput->state() == QAudio::StoppedState) { if (!m_console) { DVGui::warning( tr("Record failed: " @@ -276,7 +302,7 @@ void AudioRecordingPopup::onRecordButtonPressed() { // The audio writer support either writing to buffer or directly to disk // each method have their own pros and cons // For now using false to mimic previous QAudioRecorder behaviour - m_audioWriterWAV->restart(m_audioInput->format()); + m_audioWriterWAV->reset(m_audioInput->format()); if (!m_audioWriterWAV->start(m_filePath.getQString(), false)) { DVGui::warning( tr("Failed to save WAV file:\nMake sure you have write permissions " @@ -332,8 +358,9 @@ void AudioRecordingPopup::onRecordButtonPressed() { } m_isPlaying = false; if (!success) { - DVGui::warning(tr( - "Failed to save WAV file:\nMake sure you have write permissions in folder.")); + DVGui::warning( + tr("Failed to save WAV file:\nMake sure you have write permissions " + "in folder.")); } } } @@ -510,15 +537,11 @@ void AudioRecordingPopup::onRefreshButtonPressed() { //----------------------------------------------------------------------------- -void AudioRecordingPopup::onInputDeviceChanged() { - reinitAudioInput(); -} +void AudioRecordingPopup::onInputDeviceChanged() { reinitAudioInput(); } //----------------------------------------------------------------------------- -void AudioRecordingPopup::onAudioSettingChanged() { - reinitAudioInput(); -} +void AudioRecordingPopup::onAudioSettingChanged() { reinitAudioInput(); } //----------------------------------------------------------------------------- @@ -634,7 +657,8 @@ void AudioRecordingPopup::hideEvent(QHideEvent *event) { //----------------------------------------------------------------------------- -void AudioRecordingPopup::enumerateAudioDevices(const QString &selectedDeviceName) { +void AudioRecordingPopup::enumerateAudioDevices( + const QString &selectedDeviceName) { const QAudioDeviceInfo &defaultDeviceInfo = QAudioDeviceInfo::defaultInputDevice(); @@ -670,15 +694,19 @@ void AudioRecordingPopup::reinitAudioInput() { .value(); int sampletype = m_comboSamplefmt->itemData(m_comboSamplefmt->currentIndex()).value(); - int bitdepth = sampletype & 56; - int channels = sampletype & 7; + int bitdepth = sampletype & 60; + int channels = sampletype & 3; QAudioFormat format; format.setSampleRate(samplerate); format.setChannelCount(channels); format.setSampleSize(bitdepth); - format.setSampleType(bitdepth == 8 ? QAudioFormat::UnSignedInt - : QAudioFormat::SignedInt); + if (bitdepth == 32) + format.setSampleType(QAudioFormat::Float); + else if (bitdepth == 8) + format.setSampleType(QAudioFormat::UnSignedInt); + else + format.setSampleType(QAudioFormat::SignedInt); format.setByteOrder(QAudioFormat::LittleEndian); format.setCodec("audio/pcm"); if (!m_audioDeviceInfo.isFormatSupported(format)) { @@ -690,7 +718,7 @@ void AudioRecordingPopup::reinitAudioInput() { // Recreate input delete m_audioInput; m_audioInput = new QAudioInput(m_audioDeviceInfo, format); - m_audioWriterWAV->restart(format); + m_audioWriterWAV->reset(format); } //----------------------------------------------------------------------------- @@ -705,30 +733,39 @@ void AudioRecordingPopup::reinitAudioInput() { AudioWriterWAV::AudioWriterWAV(const QAudioFormat &format) : m_level(0.0) , m_peakL(0.0) - , m_maxAmp(0.0) + , m_state(false) , m_wrRawB(0) , m_wavFile(NULL) , m_wavBuff(NULL) { - restart(format); + reset(format); } -bool AudioWriterWAV::restart(const QAudioFormat &format) { +bool AudioWriterWAV::reset(const QAudioFormat &format) { m_format = format; + + int samplesPerSec = m_format.sampleRate() * m_format.channelCount(); if (m_format.sampleSize() == 8) { - m_rbytesms = 1000.0 / (m_format.sampleRate() * m_format.channelCount()); - m_maxAmp = 127.0; + m_rbytesms = 1000.0 / samplesPerSec; } else if (m_format.sampleSize() == 16) { - m_rbytesms = 500.0 / (m_format.sampleRate() * m_format.channelCount()); - m_maxAmp = 32767.0; - } else { - // 32-bits isn't supported - m_rbytesms = 250.0 / (m_format.sampleRate() * m_format.channelCount()); - m_maxAmp = 1.0; + m_rbytesms = 1000.0 / 2.0 / samplesPerSec; + } else if (m_format.sampleSize() == 24) { + m_rbytesms = 1000.0 / 3.0 / samplesPerSec; + } else { // 32-bits + m_rbytesms = 1000.0 / 4.0 / samplesPerSec; } + m_wrRawB = 0; m_peakL = 0.0; + m_state = false; + if (m_wavBuff) m_wavBuff->clear(); - return this->reset(); + if (m_wavFile) { + m_wavFile->close(); + delete m_wavFile; + m_wavFile = NULL; + } + + return QIODevice::reset(); } // Just a tiny define to avoid a magic number @@ -736,6 +773,8 @@ bool AudioWriterWAV::restart(const QAudioFormat &format) { #define AWWAV_HEADER_SIZE 44 bool AudioWriterWAV::start(const QString &filename, bool useMem) { + if (m_state) return false; + open(QIODevice::WriteOnly); m_filename = filename; @@ -745,15 +784,17 @@ bool AudioWriterWAV::start(const QString &filename, bool useMem) { m_wavFile = new QFile(m_filename); if (!m_wavFile->open(QIODevice::WriteOnly | QIODevice::Truncate)) return false; - m_wavFile->seek(AWWAV_HEADER_SIZE); // skip header + m_wavFile->seek(AWWAV_HEADER_SIZE); // skip header } m_wrRawB = 0; m_peakL = 0.0; + m_state = true; return true; } bool AudioWriterWAV::stop() { + if (!m_state) return false; close(); if (m_wavBuff) { @@ -775,6 +816,7 @@ bool AudioWriterWAV::stop() { m_wrRawB = 0; m_peakL = 0.0; + m_state = false; return true; } @@ -783,7 +825,7 @@ void AudioWriterWAV::writeWAVHeader(QFile &file) { quint32 samplerate = m_format.sampleRate(); quint16 bitrate = m_format.sampleSize(); - qint64 pos = file.pos(); + qint64 pos = file.pos(); file.seek(0); QDataStream out(&file); @@ -791,7 +833,8 @@ void AudioWriterWAV::writeWAVHeader(QFile &file) { out.writeRawData("RIFF", 4); out << (quint32)(m_wrRawB + AWWAV_HEADER_SIZE); out.writeRawData("WAVEfmt ", 8); - out << (quint32)16 << (quint16)1; // magic numbers! + out << (quint32)16; // Chunk size + out << (quint16)(bitrate == 32 ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM); out << channels << samplerate; out << quint32(samplerate * channels * bitrate / 8); out << quint16(channels * bitrate / 8); @@ -817,6 +860,7 @@ qint64 AudioWriterWAV::writeData(const char *data, qint64 len) { tmp = qAbs(sdata[i] - 128); if (tmp > peak) peak = tmp; } + m_level = qreal(peak) / 127.0; } else if (m_format.sampleSize() == 16) { const qint16 *sdata = (const qint16 *)data; int slen = len / 2; @@ -824,11 +868,24 @@ qint64 AudioWriterWAV::writeData(const char *data, qint64 len) { tmp = qAbs(sdata[i]); if (tmp > peak) peak = tmp; } - } else { - // 32-bits isn't supported - peak = -1; + m_level = qreal(peak) / 32767.0; + } else if (m_format.sampleSize() == 24) { + const qint8 *sdata = (const qint8 *)data; + int slen = len / 3; + for (int i = 0; i < slen; ++i) { + tmp = qAbs(sdata[i * 3 + 2]); + if (tmp > peak) peak = tmp; + } + m_level = qreal(peak) / 127.0; + } else { // 32-bits + const float *sdata = (const float *)data; + int slen = len / 4; + for (int i = 0; i < slen; ++i) { + tmp = qAbs(sdata[i] * 32767.0f); + if (tmp > peak) peak = tmp; + } + m_level = peak; } - m_level = qreal(peak) / m_maxAmp; if (m_level > m_peakL) m_peakL = m_level; // Write to memory or disk @@ -869,7 +926,7 @@ void AudioLevelsDisplay::paintEvent(QPaintEvent *event) { QColor color; if (m_level < 0.0) { - return; // draw nothing... + return; // draw nothing... } else if (m_level < 0.5) { color = Qt::green; } else if (m_level < 0.75) { diff --git a/toonz/sources/toonz/audiorecordingpopup.h b/toonz/sources/toonz/audiorecordingpopup.h index e014957..6a07f66 100644 --- a/toonz/sources/toonz/audiorecordingpopup.h +++ b/toonz/sources/toonz/audiorecordingpopup.h @@ -30,9 +30,7 @@ class AudioWriterWAV; class AudioRecordingPopup : public DVGui::Dialog { Q_OBJECT - QPushButton - *m_recordButton, *m_refreshDevicesButton, - *m_playButton, + QPushButton *m_recordButton, *m_refreshDevicesButton, *m_playButton, *m_pauseRecordingButton, *m_pausePlaybackButton, *m_saveButton; QComboBox *m_deviceListCB; QAudioInput *m_audioInput; @@ -95,7 +93,7 @@ class AudioWriterWAV : public QIODevice { Q_OBJECT public: AudioWriterWAV(const QAudioFormat &format); - bool restart(const QAudioFormat &format); + bool reset(const QAudioFormat &format); bool start(const QString &filename, bool useMem); bool stop(); @@ -109,12 +107,12 @@ public: private: QString m_filename; QFile *m_wavFile; - QByteArray *m_wavBuff; // if not null then use memory + QByteArray *m_wavBuff; // if not null then use memory QAudioFormat m_format; - quint64 m_wrRawB; // Written raw bytes + quint64 m_wrRawB; // Written raw bytes qreal m_rbytesms; - qreal m_maxAmp; qreal m_level, m_peakL; + bool m_state; void writeWAVHeader(QFile &file); diff --git a/toonz/sources/toonzlib/txshsoundcolumn.cpp b/toonz/sources/toonzlib/txshsoundcolumn.cpp index 6a328bc..a6a64a7 100644 --- a/toonz/sources/toonzlib/txshsoundcolumn.cpp +++ b/toonz/sources/toonzlib/txshsoundcolumn.cpp @@ -953,7 +953,7 @@ TSoundTrackP TXshSoundColumn::getOverallSoundTrack(int fromFrame, int toFrame, sampleRate = f.m_sampleRate; format.m_channelCount = f.m_channelCount; channels = f.m_channelCount; - format.m_signedSample = f.m_signedSample; + format.m_sampleType = f.m_sampleType; format.m_bitPerSample = f.m_bitPerSample; bitsPerSample = f.m_bitPerSample; } @@ -973,7 +973,7 @@ TSoundTrackP TXshSoundColumn::getOverallSoundTrack(int fromFrame, int toFrame, format.m_sampleRate = 44100; format.m_bitPerSample = 16; format.m_channelCount = 1; - format.m_signedSample = true; + format.m_sampleType = TSound::INT; } #ifdef _WIN32 @@ -987,8 +987,14 @@ TSoundTrackP TXshSoundColumn::getOverallSoundTrack(int fromFrame, int toFrame, if (!ssrs.contains(format.m_sampleRate)) format.m_sampleRate = 44100; QAudioFormat qFormat; qFormat.setSampleRate(format.m_sampleRate); - qFormat.setSampleType(format.m_signedSample ? QAudioFormat::SignedInt - : QAudioFormat::UnSignedInt); + switch (format.m_sampleType) { + case TSound::INT: + qFormat.setSampleType(QAudioFormat::SignedInt); + case TSound::UINT: + qFormat.setSampleType(QAudioFormat::UnSignedInt); + case TSound::FLOAT: + qFormat.setSampleType(QAudioFormat::Float); + } qFormat.setSampleSize(format.m_bitPerSample); qFormat.setCodec("audio/pcm"); qFormat.setChannelCount(format.m_channelCount); @@ -998,10 +1004,14 @@ TSoundTrackP TXshSoundColumn::getOverallSoundTrack(int fromFrame, int toFrame, format.m_bitPerSample = qFormat.sampleSize(); format.m_channelCount = qFormat.channelCount(); format.m_sampleRate = qFormat.sampleRate(); - if (qFormat.sampleType() == QAudioFormat::SignedInt) - format.m_signedSample = true; - else - format.m_signedSample = false; + switch (qFormat.sampleType()) { + case QAudioFormat::SignedInt: + format.m_sampleType = TSound::INT; + case QAudioFormat::UnSignedInt: + format.m_sampleType = TSound::UINT; + case QAudioFormat::Float: + format.m_sampleType = TSound::FLOAT; + } } #endif // Create the soundTrack @@ -1121,8 +1131,12 @@ TSoundTrackP TXshSoundColumn::mixingTogether( // Per ora perche mov vuole solo 16 bit TSoundTrackFormat fmt = mix->getFormat(); - if (fmt.m_bitPerSample != 16) fmt.m_bitPerSample = 16; - mix = TSop::convert(mix, fmt); + if (fmt.m_bitPerSample == 8) { + fmt.m_bitPerSample = 16; + fmt.m_sampleType = TSound::INT; + // 8-bits signed don't play on windows + mix = TSop::convert(mix, fmt); + } return mix; } diff --git a/toonz/sources/toonzqt/infoviewer.cpp b/toonz/sources/toonzqt/infoviewer.cpp index feff475..30d2e31 100644 --- a/toonz/sources/toonzqt/infoviewer.cpp +++ b/toonz/sources/toonzqt/infoviewer.cpp @@ -68,6 +68,7 @@ public: eChannels, eSampleRate, eSampleSize, + eSampleType, eHowMany }; @@ -222,6 +223,7 @@ InfoViewerImp::InfoViewerImp() create(eChannels, QObject::tr("Channels: ")); create(eSampleRate, QObject::tr("Sample Rate: ")); create(eSampleSize, QObject::tr("Sample Size: ")); + create(eSampleType, QObject::tr("Sample Type: ")); m_historyLabel.setStyleSheet("color: rgb(0, 0, 200);"); m_history.setStyleSheet("font-size: 12px; font-family: \"courier\";"); @@ -275,7 +277,8 @@ QString InfoViewerImp::getTypeString() { return "Tab Scene"; else if (ext == "plt") return "Toonz Palette"; - else if (ext == "wav" || ext == "aiff" || ext == "mp3") + else if (ext == "wav" || ext == "aiff" || ext == "aif" || ext == "raw" || + ext == "mp3" || ext == "ogg" || ext == "flac") return "Audio File"; else if (ext == "mesh") return "Toonz Mesh Level"; @@ -448,6 +451,22 @@ void InfoViewerImp::setSoundInfo() { label = QString::number(sndTrack->getBitPerSample()) + " bit"; setVal(eSampleSize, label); + + switch (sndTrack->getSampleType()) { + case TSound::INT: + label = "Signed integer"; + break; + case TSound::UINT: + label = "Unsigned integer"; + break; + case TSound::FLOAT: + label = "Floating-point"; + break; + default: + label = "Unknown"; + break; + } + setVal(eSampleType, label); } //----------------------------------------------------------------