diff options
author | Daniil Cherednik <dan.cherednik@gmail.com> | 2024-06-17 20:12:45 +0000 |
---|---|---|
committer | Daniil Cherednik <dan.cherednik@gmail.com> | 2024-06-17 22:21:52 +0200 |
commit | 23a4e5f1dd7ce24f65a2af0598d1f92af4b5c424 (patch) | |
tree | 8a259ca8363c5b15fd3605b760518cb37e6ac63c /src/lib | |
parent | 73dbd1609445a0142e1e138b6b44ec6d1925cbb8 (diff) | |
download | atracdenc-23a4e5f1dd7ce24f65a2af0598d1f92af4b5c424.tar.gz |
[refactoring] move some libraries in to library directory
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/bitstream/bitstream.cpp | 88 | ||||
-rw-r--r-- | src/lib/bitstream/bitstream.h | 47 | ||||
-rw-r--r-- | src/lib/bitstream/bitstream_ut.cpp | 134 | ||||
-rw-r--r-- | src/lib/liboma/include/oma.h | 78 | ||||
-rw-r--r-- | src/lib/liboma/src/liboma.c | 321 | ||||
-rw-r--r-- | src/lib/liboma/src/tools/omacp.c | 56 | ||||
-rw-r--r-- | src/lib/liboma/src/tools/omainfo.c | 43 | ||||
-rw-r--r-- | src/lib/mdct/common.h | 47 | ||||
-rw-r--r-- | src/lib/mdct/dct.h | 31 | ||||
-rw-r--r-- | src/lib/mdct/mdct.cpp | 82 | ||||
-rw-r--r-- | src/lib/mdct/mdct.h | 182 | ||||
-rw-r--r-- | src/lib/mdct/mdct_ut.cpp | 200 |
12 files changed, 1309 insertions, 0 deletions
diff --git a/src/lib/bitstream/bitstream.cpp b/src/lib/bitstream/bitstream.cpp new file mode 100644 index 0000000..ddff907 --- /dev/null +++ b/src/lib/bitstream/bitstream.cpp @@ -0,0 +1,88 @@ +/* + * 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 <cstdint> +#include "bitstream.h" + +#ifndef BIGENDIAN_ORDER +#define NBITSTREAM__LITTLE_ENDIAN_CPU +#endif + +namespace NBitStream { + +union UBytes { + uint32_t ui = 0; + uint8_t bytes[4]; +}; + +TBitStream::TBitStream(const char* buf, int size) + : Buf(buf, buf+size) +{} + +TBitStream::TBitStream() +{} + +void TBitStream::Write(uint32_t val, int n) { + if (n > 23 || n < 0) + abort(); + const int bitsLeft = Buf.size() * 8 - BitsUsed; + const int bitsReq = n - bitsLeft; + const int bytesPos = BitsUsed / 8; + const int overlap = BitsUsed % 8; + + if (overlap || bitsReq >= 0) { + Buf.resize(Buf.size() + (bitsReq / 8 + (overlap ? 2 : 1 )), 0); + } + UBytes t; + t.ui = (val << (32 - n) >> overlap); + + for (int i = 0; i < n/8 + (overlap ? 2 : 1); ++i) { +#ifdef NBITSTREAM__LITTLE_ENDIAN_CPU + Buf[bytesPos+i] |= t.bytes[3-i]; +#else + Buf[bytesPos + i] |= t.bytes[i]; +#endif + } + + BitsUsed += n; +} + +uint32_t TBitStream::Read(int n) { + if (n >23 || n < 0) + abort(); + const int bytesPos = ReadPos / 8; + const int overlap = ReadPos % 8; + + UBytes t; + for (int i = 0; i < n/8 + (overlap ? 2 : 1); ++i) { +#ifdef NBITSTREAM__LITTLE_ENDIAN_CPU + t.bytes[3-i] = (uint8_t)Buf[bytesPos+i]; +#else + t.bytes[i] = (uint8_t)Buf[bytesPos+i]; +#endif + } + + t.ui = (t.ui << overlap >> (32 - n)); + ReadPos += n; + return t.ui; +} + +unsigned long long TBitStream::GetSizeInBits() const { + return BitsUsed; +} + +} diff --git a/src/lib/bitstream/bitstream.h b/src/lib/bitstream/bitstream.h new file mode 100644 index 0000000..cfba790 --- /dev/null +++ b/src/lib/bitstream/bitstream.h @@ -0,0 +1,47 @@ +/* + * 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 <vector> + +#include <iostream> + +namespace NBitStream { + +static inline int MakeSign(int val, unsigned bits) { + unsigned shift = 8 * sizeof(int) - bits; + union { unsigned u; int s; } v = { (unsigned) val << shift }; + return v.s >> shift; +} + +class TBitStream { + std::vector<char> Buf; + int BitsUsed = 0; + int ReadPos = 0; + public: + TBitStream(const char* buf, int size); + TBitStream(); + void Write(uint32_t val, int n); + uint32_t Read(int n); + unsigned long long GetSizeInBits() const; + uint32_t GetBufSize() const { return Buf.size(); }; + const std::vector<char>& GetBytes() const { + return Buf; + } +}; +} //NBitStream diff --git a/src/lib/bitstream/bitstream_ut.cpp b/src/lib/bitstream/bitstream_ut.cpp new file mode 100644 index 0000000..a426e7c --- /dev/null +++ b/src/lib/bitstream/bitstream_ut.cpp @@ -0,0 +1,134 @@ +/* + * 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 "bitstream.h" +#include <gtest/gtest.h> + +using namespace NBitStream; + +TEST(TBitStream, DefaultConstructor) { + TBitStream bs; + EXPECT_EQ(0u, bs.GetSizeInBits()); +} + +TEST(TBitStream, SimpleWriteRead) { + TBitStream bs; + bs.Write(5, 3); + bs.Write(true, 1); + EXPECT_EQ(4, bs.GetSizeInBits()); + EXPECT_EQ(5, bs.Read(3)); + EXPECT_EQ(true, bs.Read(1)); +} + +TEST(TBitStream, OverlapWriteRead) { + TBitStream bs; + bs.Write(101, 22); + EXPECT_EQ(22, bs.GetSizeInBits()); + + bs.Write(212, 22); + EXPECT_EQ(44, bs.GetSizeInBits()); + + bs.Write(323, 22); + EXPECT_EQ(66, bs.GetSizeInBits()); + + EXPECT_EQ(101, bs.Read(22)); + EXPECT_EQ(212, bs.Read(22)); + EXPECT_EQ(323, bs.Read(22)); +} + +TEST(TBitStream, OverlapWriteRead2) { + TBitStream bs; + bs.Write(2, 2); + bs.Write(7, 4); + bs.Write(10003, 16); + + EXPECT_EQ(2, bs.Read(2)); + EXPECT_EQ(7, bs.Read(4)); + EXPECT_EQ(10003, bs.Read(16)); +} + +TEST(TBitStream, OverlapWriteRead3) { + TBitStream bs; + bs.Write(40, 6); + bs.Write(3, 2); + bs.Write(0, 3); + bs.Write(0, 3); + bs.Write(0, 3); + bs.Write(0, 3); + + bs.Write(3, 5); + bs.Write(1, 2); + bs.Write(1, 1); + bs.Write(1, 1); + bs.Write(1, 1); + bs.Write(1, 1); + + bs.Write(0, 3); + bs.Write(4, 3); + bs.Write(35, 6); + bs.Write(25, 6); + bs.Write(3, 3); + bs.Write(32, 6); + bs.Write(29, 6); + bs.Write(3, 3); + bs.Write(36, 6); + bs.Write(49, 6); + + + + + EXPECT_EQ(40, bs.Read(6)); + EXPECT_EQ(3, bs.Read(2)); + EXPECT_EQ(0, bs.Read(3)); + EXPECT_EQ(0, bs.Read(3)); + EXPECT_EQ(0, bs.Read(3)); + EXPECT_EQ(0, bs.Read(3)); + EXPECT_EQ(3, bs.Read(5)); + + EXPECT_EQ(1, bs.Read(2)); + EXPECT_EQ(1, bs.Read(1)); + EXPECT_EQ(1, bs.Read(1)); + EXPECT_EQ(1, bs.Read(1)); + EXPECT_EQ(1, bs.Read(1)); + + EXPECT_EQ(0, bs.Read(3)); + EXPECT_EQ(4, bs.Read(3)); + EXPECT_EQ(35, bs.Read(6)); + EXPECT_EQ(25, bs.Read(6)); + EXPECT_EQ(3, bs.Read(3)); + EXPECT_EQ(32, bs.Read(6)); + EXPECT_EQ(29, bs.Read(6)); + EXPECT_EQ(3, bs.Read(3)); + EXPECT_EQ(36, bs.Read(6)); + EXPECT_EQ(49, bs.Read(6)); + +} + + +TEST(TBitStream, SignWriteRead) { + TBitStream bs; + bs.Write(MakeSign(-2, 3), 3); + bs.Write(MakeSign(-1, 3), 3); + bs.Write(MakeSign(1, 2), 2); + bs.Write(MakeSign(-7, 4), 4); + EXPECT_EQ(-2, MakeSign(bs.Read(3), 3)); + EXPECT_EQ(-1, MakeSign(bs.Read(3), 3)); + EXPECT_EQ(1, MakeSign(bs.Read(2), 2)); + EXPECT_EQ(-7, MakeSign(bs.Read(4), 4)); +} + diff --git a/src/lib/liboma/include/oma.h b/src/lib/liboma/include/oma.h new file mode 100644 index 0000000..857b0a7 --- /dev/null +++ b/src/lib/liboma/include/oma.h @@ -0,0 +1,78 @@ +/* + * 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 OMA_H +#define OMA_H + +typedef struct omafile_ctx OMAFILE; + +struct oma_info { + int codec; + int framesize; + int samplerate; + int channel_format; +}; + +enum { + OMAM_R = 0x1, + OMAM_W = 0x2, +}; + +enum { + OMAC_ID_ATRAC3 = 0, + OMAC_ID_ATRAC3PLUS = 1, + OMAC_ID_MP3 = 2, + OMAC_ID_LPCM = 3, + OMAC_ID_WMA = 5 +}; + +enum { + OMA_MONO = 0, + OMA_STEREO = 1, + OMA_STEREO_JS = 2, + OMA_3 = 3, + OMA_4 = 4, + OMA_6 = 5, + OMA_7 = 6, + OMA_8 = 7 + +}; + +typedef struct oma_info oma_info_t; +typedef int block_count_t; + +#ifdef __cplusplus +extern "C" { +#endif +int oma_get_last_err(); + +OMAFILE* oma_open(const char *path, int mode, oma_info_t *info); +int oma_close(OMAFILE* oma_file); + +block_count_t oma_read(OMAFILE *oma_file, void *ptr, block_count_t blocks); +block_count_t oma_write(OMAFILE *oma_file, const void *ptr, block_count_t blocks); + +oma_info_t* oma_get_info(OMAFILE *oma_file); +int oma_get_bitrate(oma_info_t *info); +const char *oma_get_codecname(oma_info_t *info); +#ifdef __cplusplus +} +#endif + +#endif /* OMA_H */ diff --git a/src/lib/liboma/src/liboma.c b/src/lib/liboma/src/liboma.c new file mode 100644 index 0000000..e957bd4 --- /dev/null +++ b/src/lib/liboma/src/liboma.c @@ -0,0 +1,321 @@ +/* + * 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 "../include/oma.h" + +#include <endian_tools.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <assert.h> + + +#define OMA_HEADER_SIZE 96 + +struct omafile_ctx { + FILE* file; + oma_info_t info; +}; + +static const int liboma_samplerates[8] = { 32000, 44100, 48000, 88200, 96000, 0 }; +static const char* codec_name[6] = { "ATRAC3", "ATRAC3PLUS", "MPEG1LAYER3", "LPCM", "", "OMAC_ID_WMA" }; +static char ea3_str[] = {'E', 'A', '3'}; +static int channel_id_to_format_tab[7] = { OMA_MONO, OMA_STEREO, OMA_3, OMA_4, OMA_6, OMA_7, OMA_8 }; +enum { + OMAERR_OK = 0, + OMAERR_IO = -1, + OMAERR_PERM = -2, + OMAERR_FMT = -3, + OMAERR_ENCRYPT = -4, + OMAERR_VAL = -5, + OMAERR_EOF = -6 +}; + +#ifdef _MSC_VER +__declspec(thread) int err; +#else +static __thread int err; +#endif + +int oma_get_last_err() { + return err; +} + +static void save_err(int e) { + err = e; +} + +static int oma_check_header(const char* buf) { + if (memcmp(buf, &ea3_str[0], 3) || buf[4] != 0 || buf[5] != OMA_HEADER_SIZE) { + return OMAERR_FMT; + } + return OMAERR_OK; +} + +static int oma_check_encryption(const char* buf) { + if (buf[6] == -1 && buf[7] == -1) + return OMAERR_OK; + return OMAERR_ENCRYPT; +} + +static int oma_get_samplerate_idx(int samplerate) { + if (samplerate <= 0) { + fprintf(stderr, "wrong samplerate\n"); + return -1; + } + for (int i = 0; ; i++) { + if (liboma_samplerates[i] == samplerate) + return i; + if (liboma_samplerates[i] == 0) + return -1; + } + return -1; +} + +static int oma_get_channel_idx(int channel_format) { + for (int i = 0; i < 7; i++) { + if (channel_id_to_format_tab[i] == channel_format) + return i; + } + return -1; +} + +static int oma_read_atrac3_header(uint32_t params, oma_info_t* info) { + const int js = (params >> 17) & 0x1; + const int samplerate = liboma_samplerates[(params >> 13) & 0x7]; + if (samplerate == 0) { + fprintf(stderr, "liboma: wrong samplerate params, can't read header\n"); + return -1; + } + info->codec = OMAC_ID_ATRAC3; + info->framesize = (params & 0x3FF) * 8; + info->samplerate = samplerate; + info->channel_format = js ? OMA_STEREO_JS : OMA_STEREO; + return 0; +} + +static int oma_write_atrac3_header(uint32_t *params, oma_info_t *info) { + const int channel_format = info->channel_format; + if (channel_format != OMA_STEREO_JS && channel_format != OMA_STEREO) { + fprintf(stderr, "wrong channel format\n"); + return -1; + } + const uint32_t js = channel_format == OMA_STEREO_JS; + const int samplerate_idx = oma_get_samplerate_idx(info->samplerate); + if (samplerate_idx == -1) + return -1; + const uint32_t framesz = info->framesize / 8; + if (framesz > 0x3FF) + return -1; + *params = swapbyte32_on_le((OMAC_ID_ATRAC3 << 24) | (js << 17) | ((uint32_t)samplerate_idx << 13) | framesz); + return 0; +} + +static int oma_read_atrac3p_header(uint32_t params, oma_info_t* info) { + const int channel_id = (params >> 10) & 7; + if (channel_id == 0) { + return -1; + } + const int samplerate = liboma_samplerates[(params >> 13) & 0x7]; + if (samplerate == 0) { + fprintf(stderr, "liboma: wrong samplerate params, can't read header\n"); + return -1; + } + info->codec = OMAC_ID_ATRAC3PLUS; + info->framesize = ((params & 0x3FF) * 8) + 8; + info->samplerate = samplerate; + uint32_t ch_id = (params >> 10) & 7; + info->channel_format = channel_id_to_format_tab[ch_id - 1]; + return 0; +} + +static int oma_write_atrac3p_header(uint32_t *params, oma_info_t *info) { + + const int samplerate_idx = oma_get_samplerate_idx(info->samplerate); + if (samplerate_idx == -1) + return -1; + + const uint32_t framesz = (info->framesize - 8) / 8; + if (framesz > 0x3FF) + return -1; + + const int32_t ch_id = oma_get_channel_idx(info->channel_format); + if (ch_id < 0) + return -1; + + *params = swapbyte32_on_le((OMAC_ID_ATRAC3PLUS << 24) | ((int32_t)samplerate_idx << 13) | ((ch_id + 1) << 10) | framesz); + return 0; +} + +static int oma_write_header(OMAFILE* ctx, oma_info_t *omainfo) { + if (ctx == NULL || omainfo == NULL) + return -1; + char *headerbuf = (char*)calloc(OMA_HEADER_SIZE, 1); + memcpy(headerbuf, &ea3_str[0], 3); + headerbuf[3] = 1; //??? + headerbuf[5] = OMA_HEADER_SIZE; + headerbuf[6] = 0xFF; + headerbuf[7] = 0xFF; + uint32_t *params = (uint32_t*)(headerbuf+32); + switch (omainfo->codec) { + case OMAC_ID_ATRAC3: + oma_write_atrac3_header(params, omainfo); + break; + case OMAC_ID_ATRAC3PLUS: + oma_write_atrac3p_header(params, omainfo); + break; + default: + assert(0); + break; + } + int rv = fwrite(headerbuf, sizeof(char), OMA_HEADER_SIZE, ctx->file); + if (rv != OMA_HEADER_SIZE) { + fprintf(stderr, "can't write header\n"); + rv = -1; + } + free(headerbuf); + return rv; +} + +static int oma_parse_header(OMAFILE* file) { + char buf[OMA_HEADER_SIZE]; + int read = fread(&buf[0], sizeof(char), OMA_HEADER_SIZE, file->file); + int err = 0; + uint32_t params = 0; + if (OMA_HEADER_SIZE != read) + return feof(file->file) ? OMAERR_FMT : OMAERR_IO; + + err = oma_check_header(&buf[0]); + if (OMAERR_OK != err) + return err; + + err = oma_check_encryption(&buf[0]); + if (OMAERR_OK != err) + return err; + + //detect codecs + params = ((uint8_t)buf[33]) << 16 | ((uint8_t)buf[34]) << 8 | ((uint8_t)buf[35]); + switch (buf[32]) { + case OMAC_ID_ATRAC3: + oma_read_atrac3_header(params, &file->info); + break; + case OMAC_ID_ATRAC3PLUS: + oma_read_atrac3p_header(params, &file->info); + break; + + default: + fprintf(stderr, "got unsupported format: %d\n", buf[32]); + return OMAERR_FMT; + } + + return OMAERR_OK; +} + +OMAFILE* oma_open(const char *path, int mode, oma_info_t *info) { + const static char* modes[3] = {"", "rb", "wb"}; + FILE* file = fopen(path, modes[mode]); + int err = 0; + if (NULL == file) { + return NULL; + } + + struct omafile_ctx *ctx = (struct omafile_ctx*)malloc(sizeof(struct omafile_ctx)); + if (NULL == ctx) { + goto close_ret; + } + + ctx->file = file; + if (mode == OMAM_R) { + err = oma_parse_header(ctx); + if (OMAERR_OK != err) { + goto free_close_ret; + } + } else { + if (!info) { + err = OMAERR_VAL; + goto free_close_ret; + } + memcpy(&ctx->info, info, sizeof(oma_info_t)); + err = oma_write_header(ctx, info); + } + + return ctx; + +free_close_ret: + free(ctx); + +close_ret: + save_err(err); + fclose(file); + return NULL; +} + +int oma_close(OMAFILE *ctx) { + FILE* file = ctx->file; + free(ctx); + fclose(file); + return 0; +} + +block_count_t oma_read(OMAFILE *oma_file, void *ptr, block_count_t blocks) { + size_t read = fread(ptr, oma_file->info.framesize, blocks, oma_file->file); + if (read == blocks) + return read; + if (feof(oma_file->file)) { + save_err(OMAERR_EOF); + return 0; + } + return -1; +} + +block_count_t oma_write(OMAFILE *oma_file, const void *ptr, block_count_t blocks) { + size_t writen = fwrite(ptr, oma_file->info.framesize, blocks, oma_file->file); + if (writen == blocks) + return writen; + return -1; +} + +oma_info_t* oma_get_info(OMAFILE *oma_file) { + if (oma_file == NULL) + return NULL; + return &oma_file->info; +} +int oma_get_bitrate(oma_info_t *info) { + switch (info->codec) { + case OMAC_ID_ATRAC3: + return info->samplerate * info->framesize * 8 / 1024; + break; + case OMAC_ID_ATRAC3PLUS: + return info->samplerate * info->framesize * 8 / 2048; + break; + default: + return -1; + } + return -1; +} + +const char *oma_get_codecname(oma_info_t *info) { + if (info == NULL) + return ""; + int id = info->codec; + if (id < 0 || id > 5) + return ""; + return codec_name[id]; +} diff --git a/src/lib/liboma/src/tools/omacp.c b/src/lib/liboma/src/tools/omacp.c new file mode 100644 index 0000000..b938f04 --- /dev/null +++ b/src/lib/liboma/src/tools/omacp.c @@ -0,0 +1,56 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> + +#include "oma.h" + +int main(int argc, char* const* argv) { + if (3 != argc) + fprintf(stdout, "usage: \n\t omainfo [in] [out]\n"); + + OMAFILE* infile = oma_open(argv[1], OMAM_R, NULL); + if (NULL == infile) + fprintf(stderr, "Can't open %s to read, err: %d\n", argv[1], oma_get_last_err()); + + oma_info_t *info = oma_get_info(infile); + const char *codecname = oma_get_codecname(info); + const int bitrate = oma_get_bitrate(info); + + fprintf(stdout, "codec: %s, bitrate: %d, channel format: %d\n", codecname, bitrate, info->channel_format); + + OMAFILE* outfile = oma_open(argv[2], OMAM_W, info); + if (NULL == outfile) + fprintf(stderr, "Can't open %s to write, err: %d\n", argv[2], oma_get_last_err()); + + char* buf = (char*)malloc(info->framesize); + for (;;) { + block_count_t rcount = oma_read(infile, buf, 1); + if (rcount == 0) + break; + if (rcount == -1) { + fprintf(stderr, "read error\n"); + break; + } + if (oma_write(outfile, buf, 1) == -1) { + fprintf(stderr, "write error\n"); + break; + } + } +} diff --git a/src/lib/liboma/src/tools/omainfo.c b/src/lib/liboma/src/tools/omainfo.c new file mode 100644 index 0000000..1edee98 --- /dev/null +++ b/src/lib/liboma/src/tools/omainfo.c @@ -0,0 +1,43 @@ +/* + * 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 <stdio.h> + +#include "oma.h" + +int main(int argc, char* const* argv) { + fprintf(stderr, "%d\n", argc); + if (2 > argc) { + fprintf(stdout, "usage: \n\t omainfo [filename]\n"); + return 1; + } + + for (int i = 1; i < argc; i++) { + OMAFILE* file = oma_open(argv[i], OMAM_R, NULL); + if (NULL == file) + fprintf(stderr, "Can't open %s\n", argv[i]); + + oma_info_t *info = oma_get_info(file); + const char *codecname = oma_get_codecname(info); + const int bitrate = oma_get_bitrate(info); + + fprintf(stdout, "%s codec: %s, bitrate: %d, channelformat: %d framesz: %d\n", argv[i], codecname, bitrate, info->channel_format, info->framesize); + oma_close(file); + } + return 0; +} diff --git a/src/lib/mdct/common.h b/src/lib/mdct/common.h new file mode 100644 index 0000000..9b3c893 --- /dev/null +++ b/src/lib/mdct/common.h @@ -0,0 +1,47 @@ +/* + * 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 "../config.h" + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#ifdef CONFIG_DOUBLE +typedef double FLOAT; +#define FCONST(X) (X) +#define AFT_COS cos +#define AFT_SIN sin +#define AFT_TAN tan +#define AFT_LOG10 log10 +#define AFT_EXP exp +#define AFT_FABS fabs +#define AFT_SQRT sqrt +#define AFT_EXP exp +#else +typedef float FLOAT; +#define FCONST(X) (X##f) +#define AFT_COS cosf +#define AFT_SIN sinf +#define AFT_TAN tanf +#define AFT_LOG10 log10f +#define AFT_FABS fabsf +#define AFT_SQRT sqrtf +#define AFT_EXP expf +#endif diff --git a/src/lib/mdct/dct.h b/src/lib/mdct/dct.h new file mode 100644 index 0000000..55b81a9 --- /dev/null +++ b/src/lib/mdct/dct.h @@ -0,0 +1,31 @@ +/* + * 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 + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct atde_dct_ctx *atde_dct_ctx_t; + +atde_dct_ctx_t atde_create_dct4_16(float scale); +void atde_free_dct_ctx(atde_dct_ctx_t ctx); +void atde_do_dct4_16(atde_dct_ctx_t ctx, const float* in, float* out); + +#ifdef __cplusplus +} +#endif diff --git a/src/lib/mdct/mdct.cpp b/src/lib/mdct/mdct.cpp new file mode 100644 index 0000000..74b6d91 --- /dev/null +++ b/src/lib/mdct/mdct.cpp @@ -0,0 +1,82 @@ +/* + * 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 "mdct.h" +#include "dct.h" +#include <iostream> + +namespace NMDCT { + +static std::vector<TFloat> CalcSinCos(size_t n, TFloat scale) +{ + std::vector<TFloat> tmp(n >> 1); + const TFloat alpha = 2.0 * M_PI / (8.0 * n); + const TFloat omiga = 2.0 * M_PI / n; + scale = sqrt(scale/n); + for (size_t i = 0; i < (n >> 2); ++i) { + tmp[2 * i + 0] = scale * cos(omiga * i + alpha); + tmp[2 * i + 1] = scale * sin(omiga * i + alpha); + } + return tmp; +} + +TMDCTBase::TMDCTBase(size_t n, TFloat scale) + : N(n) + , SinCos(CalcSinCos(n, scale)) +{ + FFTIn = (kiss_fft_cpx*) malloc(sizeof(kiss_fft_cpx) * N >> 2); + FFTOut = (kiss_fft_cpx*) malloc(sizeof(kiss_fft_cpx) * N >> 2); + FFTPlan = kiss_fft_alloc(N >> 2, false, nullptr, nullptr); +} + +TMDCTBase::~TMDCTBase() +{ + kiss_fft_free(FFTPlan); + free(FFTOut); + free(FFTIn); +} + +} // namespace NMDCT + +struct atde_dct_ctx { + atde_dct_ctx(float scale) + : mdct(scale) + {} + NMDCT::TMIDCT<32, float> mdct; +}; + +atde_dct_ctx_t atde_create_dct4_16(float scale) +{ + return new atde_dct_ctx(32.0 * scale); +} + +void atde_free_dct_ctx(atde_dct_ctx_t ctx) +{ + delete ctx; +} + +void atde_do_dct4_16(atde_dct_ctx_t ctx, const float* in, float* out) +{ + //TODO: rewrire more optimal + const auto& x = ctx->mdct(in); + + for (int i = 0; i < 16; i++) { + out[i] = x[i + 8] * -1.0; + } +} + diff --git a/src/lib/mdct/mdct.h b/src/lib/mdct/mdct.h new file mode 100644 index 0000000..59b9af7 --- /dev/null +++ b/src/lib/mdct/mdct.h @@ -0,0 +1,182 @@ +/* + * 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 "config.h" +#include "fft/kissfft_impl/kiss_fft.h" +#include <vector> +#include <type_traits> + +namespace NMDCT { + +static_assert(sizeof(kiss_fft_scalar) == sizeof(TFloat), "size of fft_scalar is not equal to size of TFloat"); + +class TMDCTBase { +protected: + const size_t N; + const std::vector<TFloat> SinCos; + kiss_fft_cpx* FFTIn; + kiss_fft_cpx* FFTOut; + kiss_fft_cfg FFTPlan; + TMDCTBase(size_t n, TFloat scale); + virtual ~TMDCTBase(); +}; + + +template<size_t TN, typename TIO = TFloat> +class TMDCT : public TMDCTBase { + std::vector<TIO> Buf; +public: + TMDCT(float scale = 1.0) + : TMDCTBase(TN, scale) + , Buf(TN/2) + { + } + const std::vector<TIO>& operator()(const TIO* in) { + + const size_t n2 = N >> 1; + const size_t n4 = N >> 2; + const size_t n34 = 3 * n4; + const size_t n54 = 5 * n4; + const TFloat* cos = &SinCos[0]; + const TFloat* sin = &SinCos[1]; + + TFloat *xr, *xi, r0, i0; + TFloat c, s; + size_t n; + + xr = (TFloat*)FFTIn; + xi = (TFloat*)FFTIn + 1; + for (n = 0; n < n4; n += 2) { + r0 = in[n34 - 1 - n] + in[n34 + n]; + i0 = in[n4 + n] - in[n4 - 1 - n]; + + c = cos[n]; + s = sin[n]; + + xr[n] = r0 * c + i0 * s; + xi[n] = i0 * c - r0 * s; + } + + for (; n < n2; n += 2) { + r0 = in[n34 - 1 - n] - in[n - n4]; + i0 = in[n4 + n] + in[n54 - 1 - n]; + + c = cos[n]; + s = sin[n]; + + xr[n] = r0 * c + i0 * s; + xi[n] = i0 * c - r0 * s; + } + + kiss_fft(FFTPlan, FFTIn, FFTOut); + + xr = (TFloat*)FFTOut; + xi = (TFloat*)FFTOut + 1; + for (n = 0; n < n2; n += 2) { + r0 = xr[n]; + i0 = xi[n]; + + c = cos[n]; + s = sin[n]; + + Buf[n] = - r0 * c - i0 * s; + Buf[n2 - 1 -n] = - r0 * s + i0 * c; + } + + return Buf; + } +}; + +template<size_t TN, typename TIO = TFloat> +class TMIDCT : public TMDCTBase { + std::vector<TIO> Buf; +public: + TMIDCT(float scale = TN) + : TMDCTBase(TN, scale/2) + , Buf(TN) + {} + const std::vector<TIO>& operator()(const TIO* in) { + + const size_t n2 = N >> 1; + const size_t n4 = N >> 2; + const size_t n34 = 3 * n4; + const size_t n54 = 5 * n4; + const TFloat* cos = &SinCos[0]; + const TFloat* sin = &SinCos[1]; + + TFloat *xr, *xi, r0, i0, r1, i1; + TFloat c, s; + size_t n; + + xr = (TFloat*)FFTIn; + xi = (TFloat*)FFTIn + 1; + + for (n = 0; n < n2; n += 2) { + r0 = in[n]; + i0 = in[n2 - 1 - n]; + + c = cos[n]; + s = sin[n]; + + xr[n] = -2.0 * (i0 * s + r0 * c); + xi[n] = -2.0 * (i0 * c - r0 * s); + } + + kiss_fft(FFTPlan, FFTIn, FFTOut); + + xr = (TFloat*)FFTOut; + xi = (TFloat*)FFTOut + 1; + + for (n = 0; n < n4; n += 2) { + r0 = xr[n]; + i0 = xi[n]; + + c = cos[n]; + s = sin[n]; + + r1 = r0 * c + i0 * s; + i1 = r0 * s - i0 * c; + + Buf[n34 - 1 - n] = r1; + Buf[n34 + n] = r1; + Buf[n4 + n] = i1; + Buf[n4 - 1 - n] = -i1; + } + + for (; n < n2; n += 2) { + r0 = xr[n]; + i0 = xi[n]; + + c = cos[n]; + s = sin[n]; + + r1 = r0 * c + i0 * s; + i1 = r0 * s - i0 * c; + + Buf[n34 - 1 - n] = r1; + Buf[n - n4] = -r1; + Buf[n4 + n] = i1; + Buf[n54 - 1 - n] = i1; + } + return Buf; + } +}; + +} //namespace NMDCT diff --git a/src/lib/mdct/mdct_ut.cpp b/src/lib/mdct/mdct_ut.cpp new file mode 100644 index 0000000..31f6f81 --- /dev/null +++ b/src/lib/mdct/mdct_ut.cpp @@ -0,0 +1,200 @@ +/* + * 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 "mdct.h" +#include <gtest/gtest.h> + +#include <vector> +#include <cstdlib> + +using std::vector; +using namespace NMDCT; + +static vector<TFloat> mdct(TFloat* x, int N) { + vector<TFloat> res; + for (int k = 0; k < N; k++) { + TFloat sum = 0; + for (int n = 0; n < 2 * N; n++) + sum += x[n]* cos((M_PI/N) * ((TFloat)n + 0.5 + N/2) * ((TFloat)k + 0.5)); + + res.push_back(sum); + } + return res; +} + +static vector<TFloat> midct(TFloat* x, int N) { + vector<TFloat> res; + for (int n = 0; n < 2 * N; n++) { + TFloat sum = 0; + for (int k = 0; k < N; k++) + sum += (x[k] * cos((M_PI/N) * ((TFloat)n + 0.5 + N/2) * ((TFloat)k + 0.5))); + + res.push_back(sum); + } + return res; +} + +TEST(TMdctTest, MDCT32) { + const int N = 32; + TMDCT<N> transform(N); + vector<TFloat> src(N); + for (int i = 0; i < N; i++) { + src[i] = i; + } + const vector<TFloat> res1 = mdct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < res1.size(); i++) { + EXPECT_NEAR(res1[i], res2[i], 0.0000000001); + } +} + +TEST(TMdctTest, MDCT64) { + const int N = 64; + TMDCT<N> transform(N); + vector<TFloat> src(N); + for (int i = 0; i < N; i++) { + src[i] = i; + } + const vector<TFloat> res1 = mdct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < res1.size(); i++) { + EXPECT_NEAR(res1[i], res2[i], 0.0000000001); + } +} + +TEST(TMdctTest, MDCT128) { + const int N = 128; + TMDCT<N> transform(N); + vector<TFloat> src(N); + for (int i = 0; i < N; i++) { + src[i] = i; + } + const vector<TFloat> res1 = mdct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < res1.size(); i++) { + EXPECT_NEAR(res1[i], res2[i], 0.0000000001); + } +} + +TEST(TMdctTest, MDCT256) { + const int N = 256; + TMDCT<N> transform(N); + vector<TFloat> src(N); + for (int i = 0; i < N; i++) { + src[i] = i; + } + const vector<TFloat> res1 = mdct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < res1.size(); i++) { + EXPECT_NEAR(res1[i], res2[i], 0.00000001); + } +} + +TEST(TMdctTest, MDCT256_RAND) { + const int N = 256; + TMDCT<N> transform(N); + vector<TFloat> src(N); + for (int i = 0; i < N; i++) { + src[i] = rand(); + } + const vector<TFloat> res1 = mdct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < res1.size(); i++) { + EXPECT_NEAR(res1[i], res2[i], 0.01); + } +} + +TEST(TMdctTest, MIDCT32) { + const int N = 32; + TMIDCT<N> transform; + vector<TFloat> src(N); + for (int i = 0; i < N/2; i++) { + src[i] = i; + } + const vector<TFloat> res1 = midct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < N; i++) { + EXPECT_NEAR(res1[i], res2[i], 0.0000000001); + } +} + +TEST(TMdctTest, MIDCT64) { + const int N = 64; + TMIDCT<N> transform; + vector<TFloat> src(N); + for (int i = 0; i < N/2; i++) { + src[i] = i; + } + const vector<TFloat> res1 = midct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < N; i++) { + EXPECT_NEAR(res1[i], res2[i], 0.0000000001); + } +} + +TEST(TMdctTest, MIDCT128) { + const int N = 128; + TMIDCT<N> transform(N); + vector<TFloat> src(N); + for (int i = 0; i < N/2; i++) { + src[i] = i; + } + const vector<TFloat> res1 = midct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < N; i++) { + EXPECT_NEAR(res1[i], res2[i], 0.0000000001); + } +} + +TEST(TMdctTest, MIDCT256) { + const int N = 256; + TMIDCT<N> transform(N); + vector<TFloat> src(N); + for (int i = 0; i < N/2; i++) { + src[i] = i; + } + const vector<TFloat> res1 = midct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < N; i++) { + EXPECT_NEAR(res1[i], res2[i], 0.000000001); + } +} + +TEST(TMdctTest, MIDCT256_RAND) { + const int N = 256; + TMIDCT<N> transform(N); + vector<TFloat> src(N); + for (int i = 0; i < N/2; i++) { + src[i] = rand(); + } + const vector<TFloat> res1 = midct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < N; i++) { + EXPECT_NEAR(res1[i], res2[i], 0.01); + } +} |