#pragma once #include #include "opusenc.h" #include "os_types.h" #if defined WIN32 || defined _WIN32 # include /*GetFileType()*/ # include /*_get_osfhandle()*/ #endif #ifdef ENABLE_NLS # include # define _(X) gettext(X) #else # define _(X) (X) # define textdomain(X) # define bindtextdomain(X, Y) #endif #ifdef gettext_noop # define N_(X) gettext_noop(X) #else # define N_(X) (X) #endif /* Macros for handling potentially large file offsets */ #if defined WIN32 || defined _WIN32 # define OFF_T __int64 /* On Windows, fseek() on pipes may return zero even though it doesn't seek. */ # if defined __MINGW32__ || defined __MINGW64__ # define FSEEK(s,o,w) (((GetFileType((HANDLE)_get_osfhandle(_fileno(s)))&~FILE_TYPE_REMOTE)==FILE_TYPE_DISK)?fseeko64((s),(o),(w)):1) # define FTELL ftello64 # else # define FSEEK(s,o,w) (((GetFileType((HANDLE)_get_osfhandle(_fileno(s)))&~FILE_TYPE_REMOTE)==FILE_TYPE_DISK)?_fseeki64((s),(o),(w)):1) # define FTELL _ftelli64 # endif #elif defined HAVE_FSEEKO # define OFF_T off_t # define FSEEK fseeko # define FTELL ftello #else # define OFF_T long # define FSEEK fseek # define FTELL ftell #endif #define READ_SIZE 256 /* Macros to read header data */ #define READ_U32_LE(buf) \ (((unsigned int)(buf)[3]<<24)|((buf)[2]<<16)|((buf)[1]<<8)|((buf)[0])) #define READ_U16_LE(buf) \ (((buf)[1]<<8)|((buf)[0]&0xff)) #define READ_U32_BE(buf) \ (((unsigned int)(buf)[0]<<24)|((buf)[1]<<16)|((buf)[2]<<8)|((buf)[3])) #define READ_U16_BE(buf) \ (((buf)[0]<<8)|((buf)[1]&0xff)) typedef struct { unsigned short format; unsigned short channels; unsigned int samplerate; unsigned int bytespersec; unsigned short align; unsigned short samplesize; unsigned int mask; } wav_fmt; #if 0 void splitpath(const char *path, char *drv, char *dir, char *name, char *ext) { const char *end; const char *p; const char *s; if (path[0] && path[1] == ':') { if (drv) { *drv++ = *path++; *drv++ = *path++; *drv = '\0'; } } else if (drv) *drv = '\0'; for (end = path; *end && *end != ':';) end++; for (p = end; p > path && *--p != '\\' && *p != '/';) if (*p == '.') { end = p; break; } if (ext) for (s = end; (*ext = *s++);) ext++; for (p = end; p > path;) if (*--p == '\\' || *p == '/') { p++; break; } if (name) { for (s = p; s < end;) *name++ = *s++; *name = '\0'; } if (dir) { for (s = path; s < p;) *dir++ = *s++; *dir = '\0'; } } #endif static void sanitize_fourcc(unsigned char *buf) { int i; for (i = 0; i < 4; ++i) if (buf[i] < ' ' || buf[i] > '~') buf[i] = '?'; } static int seek_forward(FILE *in, ogg_int64_t length) { ogg_int64_t remaining = length; while (remaining > 0) { /* When OFF_T is 64 bits, only one seek is needed and the comparison * will always be false. When OFF_T is not large enough, seek LONG_MAX * bytes at a time (the maximum offset that basic fseek() can handle). */ OFF_T seekstep = (OFF_T)remaining; if (seekstep != remaining) seekstep = LONG_MAX; if (FSEEK(in, seekstep, SEEK_CUR)) { /* Failed to seek; do it by reading. */ unsigned char buf[1024]; do { size_t readstep = remaining > 1024 ? 1024 : (size_t)remaining; readstep = fread(buf, 1, readstep, in); if (!readstep) return 0; /* Couldn't read more, can't read file */ remaining -= readstep; } while (remaining); break; } remaining -= seekstep; } return 1; } static int find_wav_chunk(FILE *in, char *type, unsigned int *len) { unsigned char buf[8]; unsigned int chunklen; while (1) { if (fread(buf, 1, 8, in) < 8) /* Suck down a chunk specifier */ return 0; /* EOF before reaching the appropriate chunk */ chunklen = READ_U32_LE(buf + 4); if (memcmp(buf, type, 4)) { sanitize_fourcc(buf); fprintf(stderr, _("Skipping chunk of type \"%.4s\", length %u\n"), buf, chunklen); if (!seek_forward(in, (ogg_int64_t)chunklen + (chunklen & 1))) return 0; } else { *len = chunklen; return 1; } } } int convert(char *path) { FILE *fin; OggOpusEnc *enc; OggOpusComments *comments; wav_fmt format; unsigned char buf[40]; unsigned int len; int error; char out_file[1024]; { char *in_file = path; char drive[3]; char dir[256]; char fname[256]; char ext[256]; splitpath(in_file, drive, dir, fname, ext); if (memcmp(".wav", ext, strlen(ext)) == 0) { sprintf_s(out_file, "%s%s%s.opus", drive, dir, fname); } } ods(path); ods(out_file); fopen_s(&fin, path, "rb"); if (!fin) { ods("[convert-fopen_s] error\n"); return 1; } // 音声のチャンネル、周波数の読み取り //if (!find_wav_chunk(fin, "fmt ", &len)) //{ // ods("[find_wav_chunk] \"fmt \" failed.\n"); // return 1; //} //format.channels = READ_U16_LE(buf + 2); //format.samplerate = READ_U32_LE(buf + 4); //if (!find_wav_chunk(fin, "data", &len)) //{ // ods("[find_wav_chunk] \"data\" failed.\n"); // return 1; //} format.samplerate = 48'000; format.channels = 2; comments = ope_comments_create(); ope_comments_add(comments, "ARTIST", "Someone"); ope_comments_add(comments, "TITLE", "Some track"); enc = ope_encoder_create_file(out_file, comments, format.samplerate, format.channels, 0, &error); if (!enc) { char errbuf[2049]; sprintf_s(errbuf, "error encoding to file %s: %s\n", out_file, ope_strerror(error)); ope_comments_destroy(comments); fclose(fin); return 1; } while (1) { short buf[2 * READ_SIZE]; int ret = fread(buf, 2 * sizeof(short), READ_SIZE, fin); if (ret > 0) { ope_encoder_write(enc, buf, ret); } else break; } ope_encoder_drain(enc); ope_encoder_destroy(enc); ope_comments_destroy(comments); fclose(fin); return 0; }