From 5fd84b9aa9218af9171defdb6f3fd3d0853149b5 Mon Sep 17 00:00:00 2001 From: Robin Davies Date: Wed, 12 Oct 2022 14:31:34 -0400 Subject: [PATCH] Support all audio formats --- CMakeLists.txt | 4 +- README.md | 2 +- debian/control | 4 +- docs/Installing.md | 4 +- docs/download.md | 4 +- docs/index.md | 2 +- src/AlsaDriver.cpp | 361 ++++++++++++++++++++++++++++++++++++++++++++- 7 files changed, 366 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b75b61..760e990 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(pipedal DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi" HOMEPAGE_URL "https://rerdavies.github.io/pipedal" ) -set (DISPLAY_VERSION "v1.0.16") +set (DISPLAY_VERSION "v1.0.17") set (CMAKE_INSTALL_PREFIX "/usr/") @@ -86,7 +86,7 @@ set(CPACK_DEBIAN_PACKAGE_SECTION sound) set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) set(CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION TRUE) #set(CPACK_DEBIAN_PACKAGE_DEPENDS "jackd2, hostapd, dnsmasq" ) -set(CPACK_DEBIAN_PACKAGE_DEPENDS "hostapd, dnsmasq authbind" ) +set(CPACK_DEBIAN_PACKAGE_DEPENDS "hostapd, dnsmasq, authbind" ) #set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm64") set(CPACK_PACKAGING_INSTALL_PREFIX /usr) set(CPACK_PROJECT_NAME ${PROJECT_NAME}) diff --git a/README.md b/README.md index a993f44..b936afe 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@
-Download: v1.0.16 +Download: v1.0.17 Website: [https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal). diff --git a/debian/control b/debian/control index e6206ea..58c4eb1 100644 --- a/debian/control +++ b/debian/control @@ -1,5 +1,5 @@ Architecture: arm64 -Depends: libstdc++6 (>= 9), libasound2 (>= 1.0.16), libc6 (>= 2.34), libgcc-s1 (>= 4.0), libjack-jackd2-0 (>= 1.9.10+20150825) | libjack-0.125, liblilv-0-0 (>= 0.22.0~dfsg0), libnl-3-200 (>= 3.2.7), libnl-genl-3-200 (>= 3.2.7), libstdc++6 (>= 11), libsystemd0 +Depends: libstdc++6 (>= 9), libasound2 (>= 1.0.17), libc6 (>= 2.34), libgcc-s1 (>= 4.0), libjack-jackd2-0 (>= 1.9.10+20150825) | libjack-0.125, liblilv-0-0 (>= 0.22.0~dfsg0), libnl-3-200 (>= 3.2.7), libnl-genl-3-200 (>= 3.2.7), libstdc++6 (>= 11), libsystemd0 Description: IoT guitar effect for Raspberry Pi IoT guitar effect pedal for Raspberry Pi, with phone-friendly web interface. Homepage: https://github.com/rerdavies/pipedal @@ -9,6 +9,6 @@ Package: pipedal Pre-Depends: hostapd;authbind Priority: optional Section: sound -Version: 1.0.16 +Version: 1.0.17 Installed-Size: 15147 diff --git a/docs/Installing.md b/docs/Installing.md index 4bf9901..51b3ef0 100644 --- a/docs/Installing.md +++ b/docs/Installing.md @@ -13,14 +13,14 @@ page_icon: img/Install4.jpg Download the most recent Debian (.deb) package for your platform: -- [Ubuntu/Raspberry Pi OS (64-bit) v1.0.16](https://github.com/rerdavies/pipedal/releases/download/v1.0.16/pipedal_1.0.16_arm64.deb) +- [Ubuntu/Raspberry Pi OS (64-bit) v1.0.17](https://github.com/rerdavies/pipedal/releases/download/v1.0.17/pipedal_1.0.17_arm64.deb) Install the package by running ``` sudo apt update cd ~/Downloads - sudo dpkg --install pipedal_1.0.16_arm64.deb + sudo dpkg --install pipedal_1.0.17_arm64.deb ``` On Raspberry Pi OS, if you have a graphical desktop installed, you can also install the package by double-clicking on the downloaded package in the File Manager. diff --git a/docs/download.md b/docs/download.md index 931684d..d13564e 100644 --- a/docs/download.md +++ b/docs/download.md @@ -4,14 +4,14 @@ Download the most recent Debian (.deb) package for your platform: -- [Ubuntu or Raspberry Pi OS (64-bit)](https://github.com/rerdavies/pipedal/releases/download/v1.0.16/pipedal_1.0.16_arm64.deb) v1.0.16 +- [Ubuntu or Raspberry Pi OS (64-bit)](https://github.com/rerdavies/pipedal/releases/download/v1.0.17/pipedal_1.0.17_arm64.deb) v1.0.17 Install the package by running ``` sudo apt update cd ~/Downloads - sudo apt-get install ./pipedal_1.0.16_arm64.deb + sudo apt-get install ./pipedal_1.0.17_arm64.deb ``` Follow the instructions in [_Configuring PiPedal After Installation_](https://rerdavies.github.io/pipedal/Configuring.html) to complete the installation. diff --git a/docs/index.md b/docs/index.md index 29aef13..b5359b9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,7 @@ -v1.0.16 +v1.0.17   diff --git a/src/AlsaDriver.cpp b/src/AlsaDriver.cpp index 9d97850..dbba000 100644 --- a/src/AlsaDriver.cpp +++ b/src/AlsaDriver.cpp @@ -88,17 +88,17 @@ namespace pipedal static AudioFormat leFormats[]{ {"32-bit float little-endian", SND_PCM_FORMAT_FLOAT_LE}, - {"24-bit little-endian in 3bytes format", SND_PCM_FORMAT_S24_3LE}, {"32-bit integer little-endian", SND_PCM_FORMAT_S32_LE}, {"24-bit little-endian", SND_PCM_FORMAT_S24_LE}, + {"24-bit little-endian in 3bytes format", SND_PCM_FORMAT_S24_3LE}, {"16-bit little-endian", SND_PCM_FORMAT_S16_LE}, }; static AudioFormat beFormats[]{ {"32-bit float big-endian", SND_PCM_FORMAT_FLOAT_BE}, - {"24-bit big-endian in 3bytes format", SND_PCM_FORMAT_S24_3BE}, {"32-bit integer big-endian", SND_PCM_FORMAT_S32_BE}, {"24-bit big-endian", SND_PCM_FORMAT_S24_BE}, + {"24-bit big-endian in 3bytes format", SND_PCM_FORMAT_S24_3BE}, {"16-bit big-endian", SND_PCM_FORMAT_S16_BE}, }; @@ -491,6 +491,47 @@ namespace pipedal snd_pcm_dump(playbackHandle, snd_output); #endif } + + int32_t EndianSwap(int32_t v) + { + int32_t b0 = v & 0xFF; + int32_t b1 = (v >> 8) & 0xFF; + int32_t b2 = (v >> 16) & 0xFF; + int32_t b3 = (v >> 24) & 0xFF; + + return (b0 << 24) | (b1 << 16) | (b2 << 8) | (b3); + } + int16_t EndianSwap(int16_t v) + { + int16_t b0 = v & 0xFF; + int16_t b1 = (v >> 8) & 0xFF; + + return (b0 << 8) | (b1); + } + void EndianSwap(float*p,float v_) + { + int32_t v = EndianSwap(*(int32_t*)&v_); + *(int32_t*)p = v; + } + + void CopyCaptureFloatBe(size_t frames) + { + int32_t *p = (int32_t *)rawCaptureBuffer; + + std::vector &buffers = this->captureBuffers; + int channels = this->captureChannels; + for (size_t frame = 0; frame < frames; ++frame) + { + for (int channel = 0; channel < channels; ++channel) + { + int32_t v = EndianSwap(*p); + ++p; + + *(int32_t*)(buffers[channel]+frame) = v; + } + } + } + void CopyCaptureFloatLe(size_t frames) { float *p = (float *)rawCaptureBuffer; @@ -507,6 +548,39 @@ namespace pipedal } } + void CopyCaptureS16Le(size_t frames) + { + int16_t *p = (int16_t *)rawCaptureBuffer; + + std::vector &buffers = this->captureBuffers; + int channels = this->captureChannels; + constexpr float scale = 1.0f / (std::numeric_limits::max() + 1L); + for (size_t frame = 0; frame < frames; ++frame) + { + for (int channel = 0; channel < channels; ++channel) + { + int16_t v = *p++; + buffers[channel][frame] = scale * v; + } + } + } + void CopyCaptureS16Be(size_t frames) + { + int16_t *p = (int16_t *)rawCaptureBuffer; + + std::vector &buffers = this->captureBuffers; + int channels = this->captureChannels; + constexpr float scale = 1.0f / (std::numeric_limits::max() + 1L); + for (size_t frame = 0; frame < frames; ++frame) + { + for (int channel = 0; channel < channels; ++channel) + { + int16_t v = EndianSwap(*p++); + buffers[channel][frame] = scale * v; + } + } + } + void CopyCaptureS32Le(size_t frames) { int32_t *p = (int32_t *)rawCaptureBuffer; @@ -523,6 +597,128 @@ namespace pipedal } } } + void CopyCaptureS24_3Le(size_t frames) + { + uint8_t *p = (uint8_t*)rawCaptureBuffer; + + std::vector &buffers = this->captureBuffers; + int channels = this->captureChannels; + constexpr float scale = 1.0f / (std::numeric_limits::max() + 1L); + for (size_t frame = 0; frame < frames; ++frame) + { + for (int channel = 0; channel < channels; ++channel) + { + int32_t v = (p[0] << 8)+(p[1] << 16) | (p[2] << 24); + p += 3; + buffers[channel][frame] = scale * v; + } + } + } + void CopyCaptureS24_3Be(size_t frames) + { + uint8_t *p = (uint8_t*)rawCaptureBuffer; + + std::vector &buffers = this->captureBuffers; + int channels = this->captureChannels; + constexpr float scale = 1.0f / (std::numeric_limits::max() + 1L); + for (size_t frame = 0; frame < frames; ++frame) + { + for (int channel = 0; channel < channels; ++channel) + { + int32_t v = (p[2] << 8)+(p[1] << 16) | (p[0] << 24); + p += 3; + buffers[channel][frame] = scale * v; + } + } + } + void CopyCaptureS24Le(size_t frames) + { + int32_t *p = (int32_t *)rawCaptureBuffer; + + std::vector &buffers = this->captureBuffers; + int channels = this->captureChannels; + constexpr float scale = 1.0f / (0x00FFFFFFL + 1L); + for (size_t frame = 0; frame < frames; ++frame) + { + for (int channel = 0; channel < channels; ++channel) + { + int32_t v = *p++; + buffers[channel][frame] = scale * v; + } + } + } + void CopyCaptureS24Be(size_t frames) + { + int32_t *p = (int32_t *)rawCaptureBuffer; + + std::vector &buffers = this->captureBuffers; + int channels = this->captureChannels; + constexpr float scale = 1.0f / (0x00FFFFFFL + 1L); + for (size_t frame = 0; frame < frames; ++frame) + { + for (int channel = 0; channel < channels; ++channel) + { + int32_t v = EndianSwap(*p++); + buffers[channel][frame] = scale * v; + } + } + } + void CopyCaptureS32Be(size_t frames) + { + int32_t *p = (int32_t *)rawCaptureBuffer; + + std::vector &buffers = this->captureBuffers; + int channels = this->captureChannels; + constexpr float scale = 1.0f / (std::numeric_limits::max() + 1L); + for (size_t frame = 0; frame < frames; ++frame) + { + for (int channel = 0; channel < channels; ++channel) + { + int32_t v = EndianSwap(*p++); + buffers[channel][frame] = scale * v; + } + } + } + void CopyPlaybackS16Le(size_t frames) + { + int16_t *p = (int16_t *)rawPlaybackBuffer; + + std::vector &buffers = this->playbackBuffers; + int channels = this->playbackChannels; + constexpr float scale = std::numeric_limits::max(); + for (size_t frame = 0; frame < frames; ++frame) + { + for (int channel = 0; channel < channels; ++channel) + { + float v = buffers[channel][frame]; + if (v > 1.0f) + v = 1.0f; + else if (v < -1.0f) + v = -1.0f; + *p++ = (int16_t)(scale * v); + } + } + } + void CopyPlaybackS16Be(size_t frames) + { + int16_t *p = (int16_t *)rawPlaybackBuffer; + + std::vector &buffers = this->playbackBuffers; + int channels = this->playbackChannels; + constexpr float scale = std::numeric_limits::max(); + for (size_t frame = 0; frame < frames; ++frame) + { + for (int channel = 0; channel < channels; ++channel) + { + float v = buffers[channel][frame]; + if (v > 1.0f) + v = 1.0f; + else if (v < -1.0f) + v = -1.0f; + *p++ = EndianSwap((int16_t)(scale * v)); + } + } + } void CopyPlaybackS32Le(size_t frames) { int32_t *p = (int32_t *)rawPlaybackBuffer; @@ -537,12 +733,123 @@ namespace pipedal float v = buffers[channel][frame]; if (v > 1.0f) v = 1.0f; - if (v < -1.0f) + else if (v < -1.0f) v = -1.0f; *p++ = (int32_t)(scale * v); } } } + void CopyPlaybackS24Le(size_t frames) + { + // 24 bits in low bits of an int32_t. + + int32_t *p = (int32_t *)rawPlaybackBuffer; + + std::vector &buffers = this->playbackBuffers; + int channels = this->playbackChannels; + constexpr float scale = 0x00FFFFFF; + for (size_t frame = 0; frame < frames; ++frame) + { + for (int channel = 0; channel < channels; ++channel) + { + float v = buffers[channel][frame]; + if (v > 1.0f) + v = 1.0f; + else if (v < -1.0f) + v = -1.0f; + *p++ = (int32_t)(scale * v); + } + } + } + void CopyPlaybackS24Be(size_t frames) + { + // 24 bits in low bits of an int32_t. + + int32_t *p = (int32_t *)rawPlaybackBuffer; + + std::vector &buffers = this->playbackBuffers; + int channels = this->playbackChannels; + constexpr float scale = 0x00FFFFFF; + for (size_t frame = 0; frame < frames; ++frame) + { + for (int channel = 0; channel < channels; ++channel) + { + float v = buffers[channel][frame]; + if (v > 1.0f) + v = 1.0f; + else if (v < -1.0f) + v = -1.0f; + *p++ = EndianSwap((int32_t)(scale * v)); + } + } + } + void CopyPlaybackS32Be(size_t frames) + { + int32_t *p = (int32_t *)rawPlaybackBuffer; + + std::vector &buffers = this->playbackBuffers; + int channels = this->playbackChannels; + constexpr float scale = std::numeric_limits::max(); + for (size_t frame = 0; frame < frames; ++frame) + { + for (int channel = 0; channel < channels; ++channel) + { + float v = buffers[channel][frame]; + if (v > 1.0f) + v = 1.0f; + else if (v < -1.0f) + v = -1.0f; + *p++ = EndianSwap((int32_t)(scale * v)); + } + } + } + void CopyPlaybackS24_3Be(size_t frames) + { + uint8_t *p = (uint8_t *)rawPlaybackBuffer; + + std::vector &buffers = this->playbackBuffers; + int channels = this->playbackChannels; + constexpr float scale = std::numeric_limits::max(); + for (size_t frame = 0; frame < frames; ++frame) + { + for (int channel = 0; channel < channels; ++channel) + { + float v = buffers[channel][frame]; + if (v > 1.0f) + v = 1.0f; + else if (v < -1.0f) + v = -1.0f; + int32_t iValue = (int32_t)(scale * v); + p[0] = (uint8_t)(iValue >> 24); + p[1] = (uint8_t)(iValue >> 16); + p[2] = (uint8_t)(iValue >> 8); + } + } + } + void CopyPlaybackS24_3Le(size_t frames) + { + uint8_t *p = (uint8_t *)rawPlaybackBuffer; + + std::vector &buffers = this->playbackBuffers; + int channels = this->playbackChannels; + constexpr float scale = std::numeric_limits::max(); + for (size_t frame = 0; frame < frames; ++frame) + { + for (int channel = 0; channel < channels; ++channel) + { + float v = buffers[channel][frame]; + if (v > 1.0f) + v = 1.0f; + else if (v < -1.0f) + v = -1.0f; + int32_t iValue = (int32_t)(scale * v); + p[0] = (uint8_t)(iValue >> 8); + p[1] = (uint8_t)(iValue >> 16); + p[2] = (uint8_t)(iValue >> 24); + } + } + } + void CopyPlaybackFloatLe(size_t frames) { float *p = (float *)rawPlaybackBuffer; @@ -558,6 +865,22 @@ namespace pipedal } } } + void CopyPlaybackFloatBe(size_t frames) + { + float *p = (float *)rawPlaybackBuffer; + + std::vector &buffers = this->playbackBuffers; + int channels = this->captureChannels; + for (size_t frame = 0; frame < frames; ++frame) + { + for (int channel = 0; channel < channels; ++channel) + { + float v = buffers[channel][frame]; + EndianSwap(p,v); + p++; + } + } + } void AllocateBuffers(std::vector &buffers, size_t n) { buffers.resize(n); @@ -709,6 +1032,7 @@ namespace pipedal snd_pcm_format_t captureFormat; snd_pcm_hw_params_get_format(captureHwParams, &captureFormat); + copyInputFn = nullptr; switch (captureFormat) { @@ -717,6 +1041,7 @@ namespace pipedal copyInputFn = &AlsaDriverImpl::CopyCaptureFloatLe; break; case SND_PCM_FORMAT_S24_3LE: + copyInputFn = &AlsaDriverImpl::CopyCaptureS24_3Le; captureSampleSize = 3; break; case SND_PCM_FORMAT_S32_LE: @@ -725,27 +1050,39 @@ namespace pipedal break; case SND_PCM_FORMAT_S24_LE: captureSampleSize = 4; + copyInputFn = &AlsaDriverImpl::CopyCaptureS24Le; break; case SND_PCM_FORMAT_S16_LE: captureSampleSize = 2; + copyInputFn = &AlsaDriverImpl::CopyCaptureS16Le; break; case SND_PCM_FORMAT_FLOAT_BE: + captureSampleSize = 4; + copyInputFn = &AlsaDriverImpl::CopyCaptureFloatBe; captureSampleSize = 4; break; case SND_PCM_FORMAT_S24_3BE: captureSampleSize = 3; + copyInputFn = &AlsaDriverImpl::CopyCaptureS24_3Be; break; case SND_PCM_FORMAT_S32_BE: + copyInputFn = &AlsaDriverImpl::CopyCaptureS32Be; captureSampleSize = 4; break; case SND_PCM_FORMAT_S24_BE: + copyInputFn = &AlsaDriverImpl::CopyCaptureS24Be; captureSampleSize = 4; break; case SND_PCM_FORMAT_S16_BE: + copyInputFn = &AlsaDriverImpl::CopyCaptureS16Be; captureSampleSize = 2; break; default: - throw PiPedalStateException("Invalid format."); + break; + } + if (copyInputFn == nullptr) + { + throw PiPedalStateException(SS("Audio input format not supported. (" << captureFormat << ")")); } captureFrameSize = captureSampleSize * captureChannels; rawCaptureBuffer = new uint8_t[captureFrameSize * bufferSize]; @@ -756,6 +1093,7 @@ namespace pipedal snd_pcm_format_t playbackFormat; snd_pcm_hw_params_get_format(playbackHwParams, &playbackFormat); + copyOutputFn = nullptr; switch (playbackFormat) { case SND_PCM_FORMAT_FLOAT_LE: @@ -763,6 +1101,7 @@ namespace pipedal copyOutputFn = &AlsaDriverImpl::CopyPlaybackFloatLe; break; case SND_PCM_FORMAT_S24_3LE: + copyOutputFn = &AlsaDriverImpl::CopyPlaybackS24_3Le; playbackSampleSize = 3; break; case SND_PCM_FORMAT_S32_LE: @@ -770,29 +1109,41 @@ namespace pipedal playbackSampleSize = 4; break; case SND_PCM_FORMAT_S24_LE: + copyOutputFn = &AlsaDriverImpl::CopyPlaybackS24Le; playbackSampleSize = 4; break; case SND_PCM_FORMAT_S16_LE: + copyOutputFn = &AlsaDriverImpl::CopyPlaybackS16Le; playbackSampleSize = 2; break; case SND_PCM_FORMAT_FLOAT_BE: + copyOutputFn = &AlsaDriverImpl::CopyPlaybackFloatBe; playbackSampleSize = 4; break; case SND_PCM_FORMAT_S24_3BE: + copyOutputFn = &AlsaDriverImpl::CopyPlaybackS24_3Be; playbackSampleSize = 3; break; case SND_PCM_FORMAT_S32_BE: + copyOutputFn = &AlsaDriverImpl::CopyPlaybackS32Be; playbackSampleSize = 4; break; case SND_PCM_FORMAT_S24_BE: + copyOutputFn = &AlsaDriverImpl::CopyPlaybackS24Be; playbackSampleSize = 4; break; case SND_PCM_FORMAT_S16_BE: + copyOutputFn = &AlsaDriverImpl::CopyPlaybackS16Be; playbackSampleSize = 2; break; default: - throw PiPedalStateException("Invalid format."); + break; } + if (copyOutputFn == nullptr) + { + throw PiPedalStateException(SS("Unsupported audio output format. (" << playbackFormat << ")")); + } + playbackFrameSize = playbackSampleSize * playbackChannels; rawPlaybackBuffer = new uint8_t[playbackFrameSize * bufferSize]; memset(rawPlaybackBuffer, 0, playbackFrameSize * bufferSize);