aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/liboma
diff options
context:
space:
mode:
authorDaniil Cherednik <dan.cherednik@gmail.com>2024-06-17 20:12:45 +0000
committerDaniil Cherednik <dan.cherednik@gmail.com>2024-06-17 22:21:52 +0200
commit23a4e5f1dd7ce24f65a2af0598d1f92af4b5c424 (patch)
tree8a259ca8363c5b15fd3605b760518cb37e6ac63c /src/lib/liboma
parent73dbd1609445a0142e1e138b6b44ec6d1925cbb8 (diff)
downloadatracdenc-23a4e5f1dd7ce24f65a2af0598d1f92af4b5c424.tar.gz
[refactoring] move some libraries in to library directory
Diffstat (limited to 'src/lib/liboma')
-rw-r--r--src/lib/liboma/include/oma.h78
-rw-r--r--src/lib/liboma/src/liboma.c321
-rw-r--r--src/lib/liboma/src/tools/omacp.c56
-rw-r--r--src/lib/liboma/src/tools/omainfo.c43
4 files changed, 498 insertions, 0 deletions
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;
+}