diff options
author | Daniil Cherednik <dan.cherednik@gmail.com> | 2019-12-30 00:13:23 +0300 |
---|---|---|
committer | Daniil Cherednik <dan.cherednik@gmail.com> | 2020-01-01 22:29:50 +0300 |
commit | 3d69df17657c40030fb486a86ef179a42b3873ca (patch) | |
tree | 56002a11e97322d6b6360b1479330ba83e87d731 | |
parent | b58f4dd8353121094acdb41ad96fbdec4a580d79 (diff) | |
download | atracdenc-3d69df17657c40030fb486a86ef179a42b3873ca.tar.gz |
Initiall support of stdin reading for windows
Expected au(snd) format, 44100hz, 16bit, stereo or mono
-rw-r--r-- | src/CMakeLists.txt | 9 | ||||
-rw-r--r-- | src/lib/endian.h | 60 | ||||
-rw-r--r-- | src/oma/liboma/src/liboma.c | 14 | ||||
-rw-r--r-- | src/platform/win/pcm_io/mf/pcm_io_mf.cpp (renamed from src/platform/win/pcm_io_mf/pcm_io_mf.cpp) | 32 | ||||
-rw-r--r-- | src/platform/win/pcm_io/mf/pcm_io_mf.h | 26 | ||||
-rw-r--r-- | src/platform/win/pcm_io/pcm_io.cpp | 64 | ||||
-rw-r--r-- | src/platform/win/pcm_io/pcm_io_impl.h | 26 | ||||
-rw-r--r-- | src/platform/win/pcm_io/win32/pcm_io_win32.cpp | 172 | ||||
-rw-r--r-- | src/platform/win/pcm_io/win32/pcm_io_win32.h | 23 |
9 files changed, 393 insertions, 33 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 019acf3..0838942 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -30,7 +30,9 @@ if (WIN32) add_compile_definitions(_CRT_SECURE_NO_WARNINGS) include_directories("platform/win/getopt") set(SOURCE_PCM_IO_LIB - platform/win/pcm_io_mf/pcm_io_mf.cpp + platform/win/pcm_io/mf/pcm_io_mf.cpp + platform/win/pcm_io/win32/pcm_io_win32.cpp + platform/win/pcm_io/pcm_io.cpp ) else() INCLUDE(FindLibSndFile) @@ -46,7 +48,10 @@ if (${BIGENDIAN}) add_compile_definitions(BIGENDIAN_ORDER) endif() -include_directories("oma/liboma/include") +include_directories( + "lib" + "oma/liboma/include" +) set(SOURCE_FFT_LIB fft/kissfft_impl/kiss_fft.c) set_source_files_properties(fft/kissfft_impl/kiss_fft.c PROPERTIES COMPILE_FLAGS -Dkiss_fft_scalar=double) diff --git a/src/lib/endian.h b/src/lib/endian.h new file mode 100644 index 0000000..519cca1 --- /dev/null +++ b/src/lib/endian.h @@ -0,0 +1,60 @@ +/* + * This file is part of AtracDEnc. + * + * AtracDEnc is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * AtracDEnc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with AtracDEnc; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LIB_ENDIAN_H +#define LIB_ENDIAN_H + +#include <stdint.h> + +static inline uint32_t swapbyte32_on_le(uint32_t in) { +#ifdef BIGENDIAN_ORDER + return in; +#else + return ((in & 0xff) << 24) | ((in & 0xff00) << 8) | ((in & 0xff0000) >> 8) | ((in & 0xff000000) >> 24); +#endif +} + +static inline uint16_t swapbyte16_on_le(uint16_t in) { +#ifdef BIGENDIAN_ORDER + return in; +#else + return ((in & 0xff) << 8) | ((in & 0xff00) >> 8); +#endif +} + +#ifdef __cplusplus + +static inline int16_t conv_ntoh(int16_t in) { + return (int16_t)swapbyte16_on_le((uint16_t)in); +} + +static inline uint16_t conv_ntoh(uint16_t in) { + return swapbyte16_on_le(in); +} + +static inline int32_t conv_ntoh(int32_t in) { + return (int32_t)swapbyte32_on_le((uint32_t)in); +} + +static inline uint32_t conv_ntoh(uint32_t in) { + return swapbyte32_on_le(in); +} + +#endif + +#endif
\ No newline at end of file diff --git a/src/oma/liboma/src/liboma.c b/src/oma/liboma/src/liboma.c index d44b490..13d3a40 100644 --- a/src/oma/liboma/src/liboma.c +++ b/src/oma/liboma/src/liboma.c @@ -19,6 +19,8 @@ #include "../include/oma.h" #include "oma_internal.h" +#include <endian.h> + #include <stdio.h> #include <stdlib.h> #include <stdint.h> @@ -42,14 +44,6 @@ enum { OMAERR_EOF = -6 }; -static uint32_t swapbyte32(uint32_t in) { -#ifdef BIGENDIAN_ORDER - return in; -#else - return ((in & 0xff) << 24 ) | ((in & 0xff00) << 8) | ((in & 0xff0000) >> 8) | ((in & 0xff000000) >> 24); -#endif -} - #ifdef _MSC_VER __declspec(thread) int err; #else @@ -127,7 +121,7 @@ static int oma_write_atrac3_header(uint32_t *params, oma_info_t *info) { fprintf(stderr, "framesize: %d\n", framesz); if (framesz > 0x3FF) return -1; - *params = swapbyte32((OMAC_ID_ATRAC3 << 24) | (js << 17) | ((uint32_t)samplerate_idx << 13) | framesz); + *params = swapbyte32_on_le((OMAC_ID_ATRAC3 << 24) | (js << 17) | ((uint32_t)samplerate_idx << 13) | framesz); return 0; } @@ -163,7 +157,7 @@ static int oma_write_atrac3p_header(uint32_t *params, oma_info_t *info) { if (ch_id < 0) return -1; - *params = swapbyte32((OMAC_ID_ATRAC3PLUS << 24) | ((int32_t)samplerate_idx << 13) | ((ch_id + 1) << 10) | framesz); + *params = swapbyte32_on_le((OMAC_ID_ATRAC3PLUS << 24) | ((int32_t)samplerate_idx << 13) | ((ch_id + 1) << 10) | framesz); return 0; } diff --git a/src/platform/win/pcm_io_mf/pcm_io_mf.cpp b/src/platform/win/pcm_io/mf/pcm_io_mf.cpp index b8ddd98..3f9ff3a 100644 --- a/src/platform/win/pcm_io_mf/pcm_io_mf.cpp +++ b/src/platform/win/pcm_io/mf/pcm_io_mf.cpp @@ -19,6 +19,9 @@ #include "../../../wav.h" #include "../../../env.h" +#include "pcm_io_mf.h" +#include "../pcm_io_impl.h" + #include <comdef.h> #include <initguid.h> @@ -213,7 +216,7 @@ public: hr = MFCreateSourceReaderFromURL(wpath.c_str(), NULL, &Reader_); if (FAILED(hr)) { - throw THException(hr, "unable to open input file"); + throw THException(hr, "qqq unable to open input file"); } hr = ConfigureAudioStream(Reader_, &MediaType_); @@ -282,7 +285,7 @@ public: if (OutFile == INVALID_HANDLE_VALUE) { hr = HRESULT_FROM_WIN32(GetLastError()); - throw THException(hr, "unable to open output file"); + throw THException(hr, "qqq2 unable to open output file"); } hr = WriteToFile(OutFile, header, sizeof(header)); @@ -347,19 +350,6 @@ public: return static_cast<size_t>(totalSamples); } - void ConvertToPcmBuffer(const BYTE* audioData, TPCMBuffer<TFloat>& buf, size_t sz, size_t shift) { - if (ChannelsNum_ == 1) { - for (size_t i = 0; i < sz; i++) { - *(buf[i + shift] + 0) = (*(int16_t*)(audioData + i * 2 + 0)) / (TFloat)32768.0; - } - } else { - for (size_t i = 0; i < sz; i++) { - *(buf[i + shift] + 0) = (*(int16_t*)(audioData + i * 4 + 0)) / (TFloat)32768.0; - *(buf[i + shift] + 1) = (*(int16_t*)(audioData + i * 4 + 2)) / (TFloat)32768.0; - } - } - } - size_t Read(TPCMBuffer<TFloat>& buf, size_t sz) override { HRESULT hr = S_OK; @@ -374,11 +364,11 @@ public: abort(); } curPos = (Buf_.size() - ConsummerPos_) / BytesPerSample_; - ConvertToPcmBuffer(Buf_.data() + ConsummerPos_, buf, curPos, 0); + ConvertToPcmBufferFromLE(Buf_.data() + ConsummerPos_, buf, curPos, 0, ChannelsNum_); ConsummerPos_ = 0; } else { // We have all data in our buffer, just convert it and shift consumer position - ConvertToPcmBuffer(Buf_.data() + ConsummerPos_, buf, sz, 0); + ConvertToPcmBufferFromLE(Buf_.data() + ConsummerPos_, buf, sz, 0, ChannelsNum_); ConsummerPos_ += sizeBytes; return sz; } @@ -430,10 +420,10 @@ public: if (sizeBytes > (readyToRead + (curPos * BytesPerSample_))) { const size_t ready = readyToRead / BytesPerSample_; - ConvertToPcmBuffer(audioData, buf, ready, curPos); + ConvertToPcmBufferFromLE(audioData, buf, ready, curPos, ChannelsNum_); curPos += ready; } else { - ConvertToPcmBuffer(audioData, buf, sz - curPos, curPos); + ConvertToPcmBufferFromLE(audioData, buf, sz - curPos, curPos, ChannelsNum_); size_t leftBytes = readyToRead - (sz - curPos) * BytesPerSample_; Buf_.resize(leftBytes); std::memcpy(Buf_.data(), audioData + (sz - curPos) * BytesPerSample_, leftBytes); @@ -484,10 +474,10 @@ private: HANDLE OutFile = NULL; }; -IPCMProviderImpl* CreatePCMIOReadImpl(const std::string& path) { +IPCMProviderImpl* CreatePCMIOMFReadImpl(const std::string& path) { return new TPCMIOMediaFoundationFile(path); } -IPCMProviderImpl* CreatePCMIOWriteImpl(const std::string& path, int channels, int sampleRate) { +IPCMProviderImpl* CreatePCMIOMFWriteImpl(const std::string& path, int channels, int sampleRate) { return new TPCMIOMediaFoundationFile(path, channels, sampleRate); }
\ No newline at end of file diff --git a/src/platform/win/pcm_io/mf/pcm_io_mf.h b/src/platform/win/pcm_io/mf/pcm_io_mf.h new file mode 100644 index 0000000..71b18d1 --- /dev/null +++ b/src/platform/win/pcm_io/mf/pcm_io_mf.h @@ -0,0 +1,26 @@ +/* + * This file is part of AtracDEnc. + * + * AtracDEnc is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * AtracDEnc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with AtracDEnc; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include <string> + +class IPCMProviderImpl; + +IPCMProviderImpl* CreatePCMIOMFReadImpl(const std::string& path); +IPCMProviderImpl* CreatePCMIOMFWriteImpl(const std::string& path, int channels, int sampleRate);
\ No newline at end of file diff --git a/src/platform/win/pcm_io/pcm_io.cpp b/src/platform/win/pcm_io/pcm_io.cpp new file mode 100644 index 0000000..fb44cc0 --- /dev/null +++ b/src/platform/win/pcm_io/pcm_io.cpp @@ -0,0 +1,64 @@ +/* + * This file is part of AtracDEnc. + * + * AtracDEnc is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * AtracDEnc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with AtracDEnc; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "pcm_io_impl.h" +#include "mf/pcm_io_mf.h" +#include "win32/pcm_io_win32.h" + +#include <endian.h> + +#include <iostream> +#include <windows.h> + + +void ConvertToPcmBufferFromLE(const BYTE* audioData, TPCMBuffer<TFloat>& buf, size_t sz, size_t shift, size_t channelsNum) { + if (channelsNum == 1) { + for (size_t i = 0; i < sz; i++) { + *(buf[i + shift] + 0) = (*(int16_t*)(audioData + i * 2 + 0)) / (TFloat)32768.0; + } + } else { + for (size_t i = 0; i < sz; i++) { + *(buf[i + shift] + 0) = (*(int16_t*)(audioData + i * 4 + 0)) / (TFloat)32768.0; + *(buf[i + shift] + 1) = (*(int16_t*)(audioData + i * 4 + 2)) / (TFloat)32768.0; + } + } +} + +void ConvertToPcmBufferFromBE(const BYTE* audioData, TPCMBuffer<TFloat>& buf, size_t sz, size_t shift, size_t channelsNum) { + if (channelsNum == 1) { + for (size_t i = 0; i < sz; i++) { + *(buf[i + shift] + 0) = conv_ntoh((*(int16_t*)(audioData + i * 2 + 0))) / (TFloat)32768.0; + } + } else { + for (size_t i = 0; i < sz; i++) { + *(buf[i + shift] + 0) = conv_ntoh((*(int16_t*)(audioData + i * 4 + 0))) / (TFloat)32768.0; + *(buf[i + shift] + 1) = conv_ntoh((*(int16_t*)(audioData + i * 4 + 2))) / (TFloat)32768.0; + } + } +} + +IPCMProviderImpl* CreatePCMIOReadImpl(const std::string& path) { + if (path == "-") { + return CreatePCMIOStreamWin32ReadImpl(); + } + return CreatePCMIOMFReadImpl(path); +} + +IPCMProviderImpl* CreatePCMIOWriteImpl(const std::string& path, int channels, int sampleRate) { + return CreatePCMIOMFWriteImpl(path, channels, sampleRate); +}
\ No newline at end of file diff --git a/src/platform/win/pcm_io/pcm_io_impl.h b/src/platform/win/pcm_io/pcm_io_impl.h new file mode 100644 index 0000000..117ebe0 --- /dev/null +++ b/src/platform/win/pcm_io/pcm_io_impl.h @@ -0,0 +1,26 @@ +/* + * This file is part of AtracDEnc. + * + * AtracDEnc is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * AtracDEnc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with AtracDEnc; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "../../../wav.h" + +#include <windows.h> + +void ConvertToPcmBufferFromLE(const BYTE* audioData, TPCMBuffer<TFloat>& buf, size_t sz, size_t shift, size_t channelsNum); +void ConvertToPcmBufferFromBE(const BYTE* audioData, TPCMBuffer<TFloat>& buf, size_t sz, size_t shift, size_t channelsNum);
\ No newline at end of file diff --git a/src/platform/win/pcm_io/win32/pcm_io_win32.cpp b/src/platform/win/pcm_io/win32/pcm_io_win32.cpp new file mode 100644 index 0000000..3454bb6 --- /dev/null +++ b/src/platform/win/pcm_io/win32/pcm_io_win32.cpp @@ -0,0 +1,172 @@ +/* + * This file is part of AtracDEnc. + * + * AtracDEnc is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * AtracDEnc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with AtracDEnc; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "../../../wav.h" +#include "../../../env.h" + +#include <endian.h> + +#include "pcm_io_win32.h" +#include "../pcm_io_impl.h" + +#include<windows.h> + +static std::string GetLastErrorAsString() +{ + DWORD errorMessageID = ::GetLastError(); + if (errorMessageID == 0) + return std::string(); + + LPSTR messageBuffer = nullptr; + size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); + + std::string message(messageBuffer, size); + + LocalFree(messageBuffer); + + return message; +} + +class TPCMIOStreamWin32 : public IPCMProviderImpl { +public: + TPCMIOStreamWin32() { + ReadHandle_ = GetStdHandle(STD_INPUT_HANDLE); + if (ReadHandle_ == INVALID_HANDLE_VALUE) { + const std::string msg = "Unable to open input stream " + GetLastErrorAsString(); + throw std::exception(msg.data()); + } + + static const DWORD headerSz = 24; + Buf_.resize(headerSz); + + DWORD read; + if (ReadFile(ReadHandle_, Buf_.data(), headerSz, &read, NULL)) { + if (read != headerSz) { + throw std::exception("Not enough data to determinate format."); + } + + const uint32_t offset = ParseHeader(); + if (offset < headerSz) { + throw std::exception("incorrect data offset"); + } + + uint32_t toSkip = offset - headerSz; + while (toSkip) { + char c; + bool success; + success = ReadFile(ReadHandle_, &c, 1, &read, NULL); + if (!success || !read) { + throw std::exception("Unable to seek to data position"); + } + toSkip--; + } + } else { + const std::string msg = "Unable to read header from pipe " + GetLastErrorAsString(); + throw std::exception(msg.data()); + } + } + + size_t Read(TPCMBuffer<TFloat>& buf, size_t sz) override { + if (Finished_) + return 0; + + DWORD bytesToRead = sz * 2 * ChannelsNum_; // 16 bit per sampple + Buf_.resize(bytesToRead); + + DWORD pos = 0; + + while (pos < bytesToRead) { + DWORD read; + bool success; + success = ReadFile(ReadHandle_, Buf_.data() + pos, bytesToRead - pos, &read, NULL); + if (!success || !read) { + Finished_ = true; + break; + } + pos += read; + } + + size_t toConvert = pos / 2 / ChannelsNum_; + ConvertToPcmBufferFromBE(Buf_.data(), buf, toConvert, 0, ChannelsNum_); + + return toConvert; + } + + size_t Write(const TPCMBuffer<TFloat>& buf, size_t sz) override { + abort(); + return 0; + } + + size_t GetChannelsNum() const override { + return ChannelsNum_; + } + + size_t GetSampleRate() const override { + return SampleRate_; + } + + size_t GetTotalSamples() const override { + return (size_t)-1; + } + +private: + static uint32_t ExtractValue(BYTE* buf) { + uint32_t tmp; + memcpy(&tmp, buf, 4); + return conv_ntoh(tmp); + } + + uint32_t ParseHeader() { + static const std::vector<BYTE> magic = { '.', 's', 'n', 'd' }; + if (!std::equal(Buf_.begin(), Buf_.begin() + magic.size(), magic.begin())) { + throw std::exception("Input stream must have AU(SND) format"); + } + + uint32_t dataOffset = ExtractValue(&Buf_[4]); + //uint32_t dataSize = ExtractValue(&Buf_[8]); + + uint32_t encoding = ExtractValue(&Buf_[12]); + if (encoding != 3) { + throw std::exception("Expected PCM 16 bit format"); + } + + uint32_t sampleRate = ExtractValue(&Buf_[16]); + if (sampleRate != 44100) { + throw std::exception("Expected 44100Hz sampe rate"); + } + + ChannelsNum_ = ExtractValue(&Buf_[20]); + if (ChannelsNum_ != 1 && ChannelsNum_ != 2) { + throw std::exception("Expected 1 or 2 channels"); + } + + return dataOffset; + } + + HANDLE ReadHandle_; + uint32_t ChannelsNum_ = 2; + const uint32_t SampleRate_ = 44100; + + std::vector<BYTE> Buf_; + bool Finished_ = false; +}; + +IPCMProviderImpl* CreatePCMIOStreamWin32ReadImpl() { + return new TPCMIOStreamWin32(); +}
\ No newline at end of file diff --git a/src/platform/win/pcm_io/win32/pcm_io_win32.h b/src/platform/win/pcm_io/win32/pcm_io_win32.h new file mode 100644 index 0000000..52b0c1c --- /dev/null +++ b/src/platform/win/pcm_io/win32/pcm_io_win32.h @@ -0,0 +1,23 @@ +/* + * This file is part of AtracDEnc. + * + * AtracDEnc is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * AtracDEnc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with AtracDEnc; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +class IPCMProviderImpl; + +IPCMProviderImpl* CreatePCMIOStreamWin32ReadImpl();
\ No newline at end of file |