2015/01/03 版
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// SYRO for volca sample
// Example
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <windows.h>
#include "korg_syro_volcasample.h"
#include "korg_syro_comp.h"
#define MAX_SYRO_DATA 10
static const BYTE WaveFileHeader[] = {
'R' , 'I' , 'F', 'F', // 'RIFF'
0x00, 0x00, 0x00, 0x00, // Size (data size + 0x24) // <- Set
'W', 'A', 'V', 'E', // 'WAVE'
'f', 'm', 't', ' ', // 'fmt '
0x10, 0x00, 0x00, 0x00, // Fmt chunk size
0x01, 0x00, // encode(wav)
0x02, 0x00, // channel = 2
0x44, 0xAC, 0x00, 0x00, // Fs (44.1kHz)
0x10, 0xB1, 0x02, 0x00, // Bytes per sec (Fs * 4)
0x04, 0x00, // Block Align (2ch,16Bit -> 4)
0x10, 0x00, // 16Bit
'd', 'a', 't', 'a', // 'data'
0x00, 0x00, 0x00, 0x00 // data size(bytes) // <- Set
};
#define WAVFMT_POS_ENCODE 0x00
#define WAVFMT_POS_CHANNEL 0x02
#define WAVFMT_POS_FS 0x04
#define WAVFMT_POS_BIT 0x0E
#define WAV_POS_RIFF_SIZE 0x04
#define WAV_POS_WAVEFMT 0x08
#define WAV_POS_DATA_SIZE 0x28
//----------------------------------------------------------------------------
// BYTE array Get Set
//----------------------------------------------------------------------------
static void SetDWORD(BYTE *pBuff, DWORD data)
{
int i;
for (i = 0; i < 4; i++) {
*pBuff++ = (BYTE)(0x000000FF & data);
data >>= 8;
}
}
//----------------------------------------------------------------------------
static DWORD GetDWORD(BYTE *pBuff)
{
int i;
DWORD data;
data = 0;
for (i = 0; i < 4; i++) {
data <<= 8;
data |= (DWORD)(pBuff[3 - i]);
}
return (data);
}
//----------------------------------------------------------------------------
static WORD GetWORD(BYTE *pBuff)
{
WORD data;
data = (WORD)pBuff[1];
data <<= 8;
data |= (WORD)pBuff[0];
return (data);
}
//----------------------------------------------------------------------------
// File Read
//----------------------------------------------------------------------------
static BYTE *read_file(char *pName, DWORD *pFileSize)
{
FILE *fp;
BYTE *pbuf;
DWORD size;
if (NULL == (fp = fopen(pName, "rb"))) {
printf (" File open error, %s \n", pName);
return (NULL);
}
// FileLength φ(.. )メモシテオコウ
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
if (NULL == (pbuf = malloc(size))) {
printf (" Not enough memory for read file.\n");
fclose(fp);
return (NULL);
}
if (fread(pbuf, 1, size, fp) < size) {
printf (" File read error, %s \n", pName);
fclose(fp);
free(pbuf);
return (NULL);
}
fclose(fp);
// アロケートされたバッファとサイズを返す
*pFileSize = size;
return (pbuf);
}
//----------------------------------------------------------------------------
// File Write
//----------------------------------------------------------------------------
static bool write_file(char *pName, BYTE *pBuff, DWORD BuffSize)
{
FILE *fp;
if (NULL == (fp = fopen(pName, "wb"))) {
printf (" File open error, %s \n", pName);
return (false);
}
if (fwrite(pBuff, 1, BuffSize, fp) < BuffSize) {
printf (" File write error(perhaps disk space is not enough), %s \n", pName);
fclose(fp);
return (false);
}
fclose(fp);
return (true);
}
//----------------------------------------------------------------------------
// 10進数値文字列取得
//----------------------------------------------------------------------------
static int get_commandline_number(char *pStr, int *pPos)
{
int result;
int pos;
char c;
result = -1; // 有効な数値文字列がない
pos = *pPos;
for ( ; ; ) {
c = pStr[pos];
if ((c < '0') || ('9' < c))
break;
c -= '0';
if (result == -1)
result = c;
else
result = result * 10 + c;
pos++;
if (1000 <= result)
break;
}
*pPos = pos;
return (result);
}
//----------------------------------------------------------------------------
// Source ファイル読込み
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// .wav 読込み DataType_Sample_Liner
//----------------------------------------------------------------------------
static bool setup_file_sample(char *pName, TSyroData *pSyroData)
{
BYTE *pWaveImage;
DWORD wav_pos, size, chunk_size;
DWORD wav_fs;
WORD num_of_ch, sample_byte;
DWORD num_of_frame;
WORD num_of_bit;
BYTE *pSrcByte;
short *pDstShort;
long Data, AddData;
WORD ch, sbyte;
// pWaveImage は read_file() で pName のサイズにアロケートされ読込まれる
// 戻り値:アロケート済バッファ NULL:read_file() 失敗
pWaveImage = read_file(pName, &size);
if (!pWaveImage) {
return (false);
}
printf ("file = %s, ", pName);
if (size <= sizeof(WaveFileHeader)) {
printf ("wav file error, too small.\n");
free(pWaveImage);
return (false);
}
// Header 'RIFF' 'WAVEfmt '
if (memcmp(pWaveImage, WaveFileHeader, 4)) {
printf ("wav file error, 'RIFF' is not found.\n");
free(pWaveImage);
return (false);
}
if (memcmp((pWaveImage + WAV_POS_WAVEFMT), (WaveFileHeader + WAV_POS_WAVEFMT), 8)) {
printf ("wav file error, 'WAVE' or 'fmt ' is not found.\n");
free(pWaveImage);
return (false);
}
// 'fmt '
wav_pos = WAV_POS_WAVEFMT + 4; // 'fmt ' pos
// Encode PCM ?
if (GetWORD(pWaveImage + wav_pos + 8 + WAVFMT_POS_ENCODE) != 1) {
printf ("wav file error, encode must be '1'.\n");
free(pWaveImage);
return (false);
}
// Channel
num_of_ch = GetWORD(pWaveImage + wav_pos + 8 + WAVFMT_POS_CHANNEL);
if ((num_of_ch != 1) && (num_of_ch != 2)) {
printf ("wav file error, channel must be 1 or 2.\n");
free(pWaveImage);
return (false);
}
// Bits 16 or 24
num_of_bit = GetWORD(pWaveImage + wav_pos + 8 + WAVFMT_POS_BIT);
if ((num_of_bit != 16) && (num_of_bit != 24)) {
printf ("wav file error, bit must be 16 or 24.\n");
free(pWaveImage);
return (false);
}
sample_byte = (num_of_bit / 8);
// Sampling Rate
wav_fs = GetDWORD(pWaveImage + wav_pos + 8 + WAVFMT_POS_FS);
// search 'data' Chunk
for ( ; ; ) {
chunk_size = GetDWORD(pWaveImage + wav_pos + 4);
if (!memcmp((pWaveImage+wav_pos), "data", 4)) {
break;
}
// 次の Chunk まで読み飛ばし
wav_pos += chunk_size + 8;
if ((wav_pos + 8) > size) {
printf ("wav file error, 'data' chunk not found.\n");
free(pWaveImage);
return (false);
}
}
if ((wav_pos + chunk_size + 8) > size) {
printf ("wav file error, illegal 'data' chunk size.\n");
free(pWaveImage);
return (false);
}
// pSyroData->pData アロケート (1ch, 16Bit) * Frame
num_of_frame = chunk_size / (num_of_ch * sample_byte);
chunk_size = (num_of_frame * 2);
pSyroData->pData = malloc(chunk_size);
if (!pSyroData->pData) {
printf ("not enough memory to setup file. \n");
free(pWaveImage);
return (false);
}
// Convert to 1ch, 16Bit
// Input Support 16 or 24 / Ch
pSrcByte = (pWaveImage + wav_pos + 8);
pDstShort = (short *)pSyroData->pData;
for ( ; ; ) {
AddData = 0;
for (ch = 0; ch < num_of_ch; ch++) {
// 24bit では 下位 8bit は使わない sample_byte: 2 or 3
Data = ((char *)pSrcByte)[sample_byte - 1];
for (sbyte = 1; sbyte < sample_byte; sbyte++) {
Data <<= 8;
Data |= pSrcByte[sample_byte - 1 - sbyte];
}
pSrcByte += sample_byte;
AddData += Data;
}
AddData /= num_of_ch;
*pDstShort++ = (short)AddData;
if (!(--num_of_frame)) {
break;
}
}
pSyroData->Size = chunk_size;
pSyroData->Fs = wav_fs;
pSyroData->SampleEndian = LittleEndian;
free(pWaveImage);
printf ("ok.\n");
return (true);
}
//----------------------------------------------------------------------------
// AllSample 読込み DataType_Sample_All
//----------------------------------------------------------------------------
static bool setup_file_all(char *pName, TSyroData *pSyroData)
{
DWORD size;
pSyroData->pData = read_file(pName, &size);
if (!pSyroData->pData) {
return false;
}
pSyroData->Size = size;
printf ("ok.\n");
return (true);
}
//----------------------------------------------------------------------------
// Pattern 読込み DataType_Pattern
//----------------------------------------------------------------------------
static bool setup_file_pattern(char *pName, TSyroData *pSyroData)
{
DWORD size;
pSyroData->pData = read_file(pName, &size);
if (!pSyroData->pData) {
return false;
}
if (size != VOLCASAMPLE_PATTERN_SIZE) {
printf (" size error\n");
free(pSyroData->pData);
pSyroData->pData = NULL;
return false;
}
pSyroData->Size = size;
printf ("ok.\n");
return (true);
}
//----------------------------------------------------------------------------
// 全 Source 指示(argv[2] から) を処理
/*
analyze command line
notes : s17c15:sample.wav
TT~TT~T~~~~T~~~~~
|| || | +------- sourec file name (unnecessary when 'erase sample' is specified)
|| || +------------ partition mark (:)
|| |+-------------- compression bit (8-16), default=16
|| +--------------- compression
|+----------------- number of sample(0-99) or pattern(1-10)
+------------------ type of source file
s:sample, e:erase sample, p:pattern
*/
//----------------------------------------------------------------------------
static int analayze_commandline(int CountSource, char **ppSourceParam, TSyroData *pSyroData)
{
int CountSyroData;
int num, i, pos;
int CheckLower, CheckUpper;
int checkcomp, compbit;
char c;
TSyroDataType data_type;
CountSyroData = 0;
for (i = 0; i < CountSource; i++) {
pos = 0;
num = -1; // 'nn番目' 必須
checkcomp = 0;
compbit = 0;
CheckLower = 0;
CheckUpper = 0;
printf (" Input data %d : ", (i + 1));
// Source Type
c = ppSourceParam[i][pos++];
switch (c) {
case 'S':
case 's':
// S:Sample 00-99
data_type = DataType_Sample_Liner;
CheckLower = 0;
CheckUpper = (VOLCASAMPLE_NUM_OF_SAMPLE - 1);
checkcomp = 1;
break;
case 'E':
case 'e':
// E:Erase 00-99
data_type = DataType_Sample_Erase;
CheckLower = 0;
CheckUpper = (VOLCASAMPLE_NUM_OF_SAMPLE - 1);
checkcomp = 0;
break;
case 'P':
case 'p':
// P:Pattern 01-10
data_type = DataType_Pattern;
CheckLower = 1;
CheckUpper = VOLCASAMPLE_NUM_OF_PATTERN;
checkcomp = 0;
break;
case 'A':
case 'a':
// AllSample
data_type = DataType_Sample_All;
num = 0; // 'nn番目' 不要
checkcomp = 1;
break;
default:
printf ("Unknown data type '%c' \n", c);
continue;
}
// Sample/Erase/Pattern は番号が必須
if (num == -1) {
num = get_commandline_number(ppSourceParam[i], &pos);
if (num == -1) {
printf (" number is not found.\n");
continue;
}
if ((num < CheckLower) || (num > CheckUpper)) {
printf (" number is out of range(legal : %d~%d). \n",
CheckLower, CheckUpper);
continue;
}
}
// 圧縮 ?
if (checkcomp) {
c = ppSourceParam[i][pos];
if ((c == 'c') || (c == 'C')) {
pos++;
compbit = 16;
if (ppSourceParam[i][pos] != ':') {
compbit = get_commandline_number(ppSourceParam[i], &pos);
if (compbit == -1) {
printf (" number of compression bit is not found.\n");
continue;
}
if ((compbit < 8) || (16 < compbit)) {
printf (" number of compression bit is out of range(legal : 8~16).\n");
continue;
}
}
}
}
// 「Source指示」の後は ':' (partition mark) 必須
c = ppSourceParam[i][pos++];
if (c != ':') {
printf (" syntax error (':' is not found).\n");
continue;
}
// pSyroData に必要情報をセットする
switch (data_type) {
case DataType_Sample_Liner:
if (compbit) {
data_type = DataType_Sample_Compress;
printf (" Sample(Compress bit=%d), number = %d, ", compbit, num);
}
else {
printf (" Sample, number = %d, ", num);
}
if (!setup_file_sample(&ppSourceParam[i][pos], pSyroData)) {
continue;
}
break;
case DataType_Sample_Erase:
printf (" Sample erase, number = %d \n", num);
pSyroData->pData = NULL;
pSyroData->Size = 0;
break;
case DataType_Pattern:
printf (" Pattern, number = %d, ", num);
num--;
if (!setup_file_pattern(&ppSourceParam[i][pos], pSyroData)) {
continue;
}
break;
case DataType_Sample_All:
if (compbit) {
data_type = DataType_Sample_AllCompress;
printf (" Sample All(Compress bit=%d), ", compbit);
}
else {
printf (" Sample All, ");
}
if (!setup_file_all(&ppSourceParam[i][pos], pSyroData)) {
continue;
}
break;
default:
continue;
}
pSyroData->DataType = data_type;
pSyroData->Number = num;
if (compbit) {
pSyroData->Quality = compbit;
}
// 次の SyroData
CountSyroData++;
if (CountSyroData == MAX_SYRO_DATA)
break;
pSyroData++;
}
return (CountSyroData);
}
//----------------------------------------------------------------------------
// pSyroData 内のアロケートされたメモリを開放
//----------------------------------------------------------------------------
static void free_syrodata(TSyroData *pSyroData, int CountSyroData)
{
int i;
for (i = 0; i < CountSyroData; i++) {
if (pSyroData->pData) {
free(pSyroData->pData);
pSyroData->pData = NULL;
}
pSyroData++;
}
}
//----------------------------------------------------------------------------
// Main (Execution)
//----------------------------------------------------------------------------
static int main2(int argc, char *argv[])
{
TSyroData SyroData[MAX_SYRO_DATA];
SyroStatus status;
TSyroHandle handle;
int CountSource;
DWORD TotalFrames;
BYTE *pTargetImage;
DWORD SizeTarget;
BYTE *pSet;
short left, right;
// command-line : ExeName TargetWav SourceCmd[ SourceCmd[...]]
if (argc <= 2) {
printf (" Syntax : >%s generate_file_name.wav src_file1 src_file2 .... \n", argv[0]);
return (1);
}
// 全ての Source 情報を SyroData に格納
memset(SyroData, 0, sizeof(SyroData));
CountSource = analayze_commandline((argc - 2), &(argv[2]), SyroData);
if (!CountSource) {
printf (" Effective file is not found. \n");
return (1);
}
// Start Syro Function
status = SyroVolcaSample_Start(&handle, SyroData, CountSource, 0, &TotalFrames);
if (status != Status_Success) {
printf (" Start error, %d \n", status);
free_syrodata(SyroData, CountSource);
return (1);
}
// .wav Image アロケート
SizeTarget = (TotalFrames * 4) + sizeof(WaveFileHeader);
pTargetImage = malloc(SizeTarget);
if (!pTargetImage) {
printf (" Not enough memory for write file.\n");
SyroVolcaSample_End(handle);
free_syrodata(SyroData, CountSource);
return (1);
}
// .wav Image Header
memcpy(pTargetImage, WaveFileHeader, sizeof(WaveFileHeader));
SetDWORD((pTargetImage + WAV_POS_RIFF_SIZE), ((TotalFrames * 4) + 0x24));
SetDWORD((pTargetImage + WAV_POS_DATA_SIZE), (TotalFrames * 4));
// .wav Image Data
pSet = pTargetImage + sizeof(WaveFileHeader);
while (TotalFrames) {
// Convert Syro Function
SyroVolcaSample_GetSample(handle, &left, &right);
*pSet++ = (BYTE)left;
*pSet++ = (BYTE)(left >> 8);
*pSet++ = (BYTE)right;
*pSet++ = (BYTE)(right >> 8);
TotalFrames--;
}
// End Syro Function
SyroVolcaSample_End(handle);
free_syrodata(SyroData, CountSource);
// Target Write .wav Image
if (write_file(argv[1], pTargetImage, SizeTarget)) {
printf (" Complete to convert.\n");
}
free(pTargetImage);
return (0);
}
//----------------------------------------------------------------------------
// Main (Wrapper)
//----------------------------------------------------------------------------
int main(int argc, char *argv[])
{
int ret;
ret = main2(argc, argv);
return (ret);
}