#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#ifdef STDC_HEADERS
#include <string.h>
#include <ctype.h>
#elif HAVE_STRINGS_H
#include <strings.h>
#endif
#include "timidity.h"
#include "common.h"
#include "output.h"
#include "tables.h"
#include "controls.h"
#include "audio_cnv.h"

//オリジナルの output.c と内容的にはほぼ同じだが、
//オリジナルを使うとリンカエラーになる
//（リンカエラーを回避することも出来るが、ファイルサイズが大きくなる）

/*****************************************************************/
/* Some functions to convert signed 32-bit data to other formats */

static void  s32tos16(int32 *lp, int32 c)
{
  int16 *sp=(int16 *)(lp);
  int32 l, i;

  for(i = 0; i < c; i++)
    {
      l=(lp[i])>>(32-16-GUARD_BITS);
      if (l > 32767) l=32767;
      else if (l<-32768) l=-32768;
      sp[i] = (int16)(l);
    }
}

#define MAX_24BIT_SIGNED (8388607)
#define MIN_24BIT_SIGNED (-8388608)

#define STORE_S24_LE(cp, l) *cp++ = l & 0xFF, *cp++ = l >> 8 & 0xFF, *cp++ = l >> 16
#define STORE_S24  STORE_S24_LE

static void s32tos24(int32 *lp, int32 c)
{
	uint8 *cp = (uint8 *)(lp);
	int32 l, i;

	for(i = 0; i < c; i++)
	{
		l = (lp[i]) >> (32 - 24 - GUARD_BITS);
		l = (l > MAX_24BIT_SIGNED) ? MAX_24BIT_SIGNED
				: (l < MIN_24BIT_SIGNED) ? MIN_24BIT_SIGNED : l;
		STORE_S24(cp, l);
	}
}

// return: number of bytes 
int32 general_output_convert(int32 *buf, int32 count)
{//stereo かつ
 //16bit or 24bit
 //であることが前提
    int32 bytes;
    count *= 2; // Stereo samples
    bytes = count;
    if(play_mode->encoding & PE_16BIT){
    	bytes *= 2;
        s32tos16(buf, count);
    }
	else if(play_mode->encoding & PE_24BIT) {
		bytes *= 3;
        s32tos24(buf, count);
    }
	//else if(play_mode->encoding & PE_32BIT) {//未対応
	//  bytes *= 4;
    //  s32tos32(buf, count);//何もしないのと同じ。
    //}
    else{
         //この部分を通ることはあり得ないはず。
    }
    return bytes;
}

int32 apply_encoding(int32 old_enc, int32 new_enc)
{
	const int32 mutex_flags[] = {
		PE_16BIT | PE_24BIT | PE_ULAW | PE_ALAW,
		PE_BYTESWAP | PE_ULAW | PE_ALAW,
		PE_SIGNED | PE_ULAW | PE_ALAW,
	};
	int i;

	for (i = 0; i < sizeof mutex_flags / sizeof mutex_flags[0]; i++) {
		if (new_enc & mutex_flags[i])
			old_enc &= ~mutex_flags[i];
	}
	return old_enc | new_enc;
}
