#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fmcfrb.h>
#include <snd.h>

#include "calc   .h"
#include "str_sub.h"
#include "graphic.h"

#define BEEP_CLK()		BPB_freeon2(  4,2000 )
#define BEEP_DMY()		BPB_freeon2( 30, 400 )
#define BEEP_CAU()		BPB_freeon2(  4,1000 )
#define VOICE_LMT		( 64 * 1024 )

char	swork[16*1024] ;
char	snd_stock[VOICE_LMT], *snd_cur ;
struct { char *p ; int note ; } snd_idx[10] ;
int 	snd_n, snd_size, voice_ch ;
int 	_disp_status_flag = 0 ;

/***  パッド用方向テーブル  sel,sta,Ｂ,Ａ,右,左,下,上  ***/
struct	{ int x,y ;}
		ang_p[9]={ 0,-1, 1,-1, 1,0, 1,1, 0,1, -1,1, -1,0, -1,-1, 0,0 };
int		pad_ang[16]= {-1,4, 0,-1, 2,3, 1,2,  6, 5, 7, 6, -1,4, 0,-1};
int		joy_ang[16]= {-1,0,128,-1,192,224,160,192,64,32,96,64,-1,0,128,-1};
int		bit_ang[16]= { 8,4,0,8, 2,3,1,2, 6,5,7,6, 8,4,0,8 };

/***  トリガー押し待ち  ***/

void wait_trgrel( int port )
{
	int pad ;

	do SND_joy_in_2( port, &pad ); while ( ( ~pad & 0xf0 )!= 0 );
}

int wait_trig( int port, int rel )
{
	int trig ;

	if( rel ) wait_trgrel( port );

	do{
		SND_joy_in_2( port, &trig ), trig = ( ~trig >>4 )& 15 ;
	}while( trig == 0 );

	return trig ;
}

void break_point( int n )
{
	char	tmp[80];
	int		pad, x, y ;

	if( _disp_status_flag )	x = 8, y = 400 ;
	 else					x = ( 640 - 17*8 )/ 2, y = 464 ;
	strcpy( tmp, "break-point " ), strcat( tmp + 12, set_num( n, 5 ) );
	symbol(  x, y+15, tmp, 1,1, 15,0, OPAQUE, 0 );
	do SND_joy_in_1( 1, &pad ); while( ( ~pad & 0x30 )!= 0 );
	do SND_joy_in_1( 1, &pad ); while( ( ~pad & 0x30 )== 0 );
	do SND_joy_in_1( 1, &pad ); while( ( ~pad & 0x30 )!= 0 );
	box_fill( x, y, 17*8, 16, PSET, 0,0 );
}

void _disp_status( int n, char *msg, int x, int y )
{
	char	tmp[80];
	int		len ;

	if( 8 < ( len = strlen( msg ) ) ) len = 8 ;
	strcpy( tmp, "         (" ),	memcpy( tmp, msg, len );
	strcat( tmp, set_num( x, 5 ) ), strcat( tmp, "," );
	strcat( tmp, set_num( y, 5 ) ), strcat( tmp, ")" );
	symbol ( 160, 400 + n*16 + 15, tmp, 1,1, 15,0, OPAQUE, 0 );
	_disp_status_flag = 1 ;
}

/***  ＰＭＢファイルと、ＳＮＤファイルが、同時に読み込める。  ***/

int sound_load( char *nam )
{
	int 	size ;
	char	header[32];
	FILE	*fp;

	if( ( fp = fopen( nam, "rb" ) )== NULL ) return 1 ;

	fread( header, 32, 1, fp );
	size = *(long *)( header + 12 )+ 32 ;
	if( snd_n == 0 ) snd_cur = snd_stock, snd_size = 0 ;
	if( VOICE_LMT <= snd_size + size ) return 2 ;

	snd_idx[ snd_n ].note	= header[28] ;
	snd_idx[ snd_n ].p		= snd_cur ;
	fseek( fp, 0, SEEK_SET );
	fread( snd_cur, size, 1 , fp );
	snd_cur += size, snd_size+= size, snd_n++ ;

	fclose(fp);

	return 0 ;
}

int sound_init( char *fbuf )
{
	char *np, name[80], bankname[8];
	int sel, err_n ;

	SND_elevol_init();
	SND_elevol_mute( 0x31 ), SND_elevol_set( 1, 127, 127 );
	snd_n = voice_ch = err_n = sel = 0 ;

	do{
		np = name ;
		while( *fbuf != '\n' && *fbuf != '\0' ) *np++ = *fbuf++ ;
		*np++ = '\0' ;

		if( *name != '\0' ){
			switch( sel ){
			case 0 : err_n = SND_pcm_bank_load( name, bankname )	; break ;
			case 1 : err_n = sound_load( (char *)name )				; break ;
			}
		}
		sel = 1 ;
	}while( *fbuf++ == '\n' && err_n == 0 );

	if( SND_pcm_mode_set( 1 )==5 ) BEEP_DMY();
	return err_n ;
}

int sound_end()
{
	snd_n = 0 ;
	SND_elevol_init(), SND_end();
	return 0;
}

void voice( int ch, int vol, int n )
{
	if( n < 0 || snd_n + 32 <= n ) return ;
	ch = ( n < 32 ? 64 + ch : 64 + 7 );
	SND_pan_set( ch, 64 );

	if( n < 32 ){
		SND_key_off		( ch );
		SND_inst_change	( ch, n );
		SND_key_on		( ch, 60, vol );
	}else{
		SND_pcm_play_stop( ch );
		SND_pcm_play( ch, 60, vol, snd_idx[ n - 32 ].p );
	}
}

void dim_voice( int n, int vol, int dx, int dy )
{
	int ch, abs_x, abs_y, v_vol, v_pan ;

	if( n < 0 || snd_n + 32 <= n ) return ;
	if( n < 32 ){
		ch = 64 + voice_ch, ++voice_ch, voice_ch %= 7 ;
	}else{
		ch = 64 + 7 ;
	}
	abs_x = ABS( dx ), abs_y = ABS( dy );
	v_vol = vol - ( abs_x > abs_y ? abs_x : abs_y )/ 8 ;
	v_pan = 64 +( dx / 8 );
	v_pan = ( v_pan < 0 ? 0 :( v_pan < 127 ? v_pan : 127 ) );

	if( n < 32 ){
		SND_key_off		( ch );
		SND_inst_change	( ch, n );
		SND_pan_set		( ch, v_pan );
		SND_key_on		( ch, 60, v_vol );
	}else{
		SND_pcm_play_stop( ch );
		SND_pan_set ( ch, v_pan );
		SND_pcm_play( ch, 60, v_vol, snd_idx[ n - 32 ].p );
	}
}
