// Interface to Mikropuhe for writing files.
// TAB=3 spaces
//
// Some key points:
//
// - Interface is a DLL loaded at program's startup or when needed and unloaded when speech is no longer needed
// - OLE/SAPI is not used at all
//

#ifdef TH_LINUX
	// Linux
	#define TH_STDCALL	_cdecl
#else
	// Win32
	#define TH_STDCALL	__stdcall
#endif


// DLL function type definitions - taken from atl.h
#if defined(MPINT_DLLIMPORT)

	// If using import library
	#ifdef __cplusplus
		#define MPINTAPI extern "C" long __declspec(dllimport) TH_STDCALL
		#define MPINTAPI_(x) extern "C" __declspec(dllimport) x TH_STDCALL
	#else
		#define MPINTAPI long __declspec(dllimport) TH_STDCALL
		#define MPINTAPI_(x) __declspec(dllimport) x TH_STDCALL
	#endif

#elif defined(MPINT_DLLIMPLEMENT)

	// When building Mikropuhe DLL
	#ifdef __cplusplus
		#ifdef TH_LINUXGCC
			#define MPINTAPI extern "C" long TH_STDCALL
			#define MPINTAPI_(x) extern "C" x TH_STDCALL
		#else
			#define MPINTAPI extern "C" long __declspec(dllexport) TH_STDCALL
			#define MPINTAPI_(x) extern "C" __declspec(dllexport) x TH_STDCALL
		#endif
	#else
		#define MPINTAPI long __declspec(dllexport) TH_STDCALL
		#define MPINTAPI_(x) __declspec(dllexport) x TH_STDCALL
	#endif

#else

	// Give the prototypes
	#define MPINTAPI extern "C" long
	#define MPINTAPI_(x) extern "C" x

	// GetProcAddress used to link to dll. No need to prototypes.
	// Or dlopen() in Linux
	//#define MPINT_NOPROTOTYPES
#endif


// Error codes
#define MPINT_ERR_GENERAL			-2001			// Unspecific error
#define MPINT_ERR_SYNTH				-2002			// Error synthesizing text
#define MPINT_ERR_MEM				-2003			// Out of memory
#define MPINT_ERR_DESTFILEOPEN	-2004			// Could not open destination file for writing
#define MPINT_ERR_DESTFILEWRITE	-2005			// Writing destination file failed (disk full?)
#define MPINT_ERR_EINVAL			-2006			// Invalid parameter


#define MPINT_ERR_INITBADKEY		-2100			// MPINT_Init called with bad key
#define MPINT_ERR_INITNOVOICES	-2101			// MPINT_Init did not find any voice files from DLLs directory (*.tdb, *.m42)
#define MPINT_ERR_INITVOICEFAIL	-2102			// MPINT_Init could not load voice file
#define MPINT_ERR_INITTEXTPARSE	-2103			// MPINT_Init could not load text parsing file (<exe-path>mpwrfile.tul or <exe-path>mpwrfile.tfg)
#define MPINT_ERR_SOUNDCARD		-2104			// Only with MPINT_Speak-call



#ifndef MPINT_SPEAKFILE_PARAMS
#define MPINT_SPEAKFILE_PARAMS

// nTags field of extended parameters for SpeakFile-call
enum {
	MPINT_TAGS_OWN = 1,			// Mikropuhe tags, Own tags are either -NOPx or _N=xxxxx (see Mikropuhe manual for details)
	MPINT_TAGS_SAPI4 = 2,		// SAPI4-tags are allowed
	MPINT_TAGS_SAPI5 = 4,		// SAPI5-tags are allowed
	//MPINT_TAGS_VXML = 8		// VoiceXML/SSML tags, they are included in sapi5 support
};


// Extended parameters for SpeakFile-call
// Always initialize this structure with memset(&rParam, 0, sizeof(rParam))
typedef struct {
	int	nTags;					// Combination of MPINT_TAGS_xxx, default=1
	int	nSaveSynthParams;		// 1=Save synthesizer settings to global settings when speaking is complete, 0=Normal operation - do not save

	int	nSampleFreq;			// Sampling frequency for the resulting file, 0=Use synthesizer's native (default)
										// (8000=Run hi-quality telephony filter, other transformations are lo-quality)
	int	nBits;					// Sample size 8 or 16 bits, default=16 bits
	int	nChannels;				// 1=Mono, 2=Stereo, default=1

	int	nWriteWavHeader;		// 0=Do not write WAV-header, 1=Write WAV-header, it's size will always be 44 bytes

	const char	*pHomePath;		// Home path for loading wav-files with tag <audio src="xxx> and .tul files with tag <mikropuhetul name="xxx">.
										// Must end with backslash or slash in Linux!
										// NULL=Use DLL's or so's home directory

	// Hook if you do want to handle data yourself instead of writing to a file. If this is set
	// pass NULL as MPINT_SpeakToFile pFileName parameter.
	// If you have specified WAV-header, length fields after 'RIFF' and 'data' blocks
	// will be zero since seeking is not supported with pfnWrite-hook
	//
	// pWriteData	-> Member variable pWriteData from this struct
	// pReserved	-> NULL, may be later used
	//
	// Return value: 0=Ok, others=Cancel SpeakToFile-call and return given value, USE POSITIVE ERROR VALUES - MP USES NEGATIVE
	int	(*pfnWrite)(const void *pData, unsigned uBytes, void *pWriteData, void *pReserved);
	void	*pWriteData;			// Data passed to pfnWrite


	// For future use, set to zero
	int	nReserved1;
	int	nReserved2;
	int	nReserved3;
	int	nReserved4;
} MPINT_SpeakFileParams;

#endif



#ifndef MPINT_NOPROTOTYPES

/////////////////////////////////////////////////////////////////////////////
// Functions that have global synthesizer settings set by MPINT_UseSettings
// You may use this or following function set or mix them as you wish.
// FEW THREADING RULES:
// 1. All functions must be called from same thread.
// 2. Exception to first rule: MPINT_SpeakFile may be called from any thread
//    after MPINT_InitEx has succeeded
// 3. Functions are not re-entrant

/*
*	Initializes the synthesizer (OBSOLETE but still in Win-version, USE MPINT_InitEx)
*	Locks internal Windows-like critical section during the call
*
*	dwKeyNumber		-> Copy protection magic number, use number given by Timehouse
*	pSettingsStr	-> String containing synthesizer's settings, ""=Use defaults
*
*	Returns: 0=Ok, MPINT_ERR_xxx=Failed and no message shown
*/
MPINTAPI MPINT_Init( unsigned long dwKeyNumber, const char *pSettingsStr );

/*
*	Initializes the synthesizer and creates global voice cache if not created already.
*	Locks internal Windows-like critical section during the call
*
*	pKey				-> Auhtorization string, obtain one from Timehouse Oy
*	pSettingsStr	-> String containing synthesizer's settings, ""=Use defaults
*	pReserved		-> For future use, use NULL
*
*	Returns: 0=Ok, MPINT_ERR_xxx=Failed and no message shown
*/
MPINTAPI MPINT_InitEx( const char *pKey, const char *pSettingsStr, void *pReserved );
typedef long (*MPINT_InitExType)(const char *, const char *, void *);	// Type for function ptr

/*
*	Uses given settings. Use this to change settings if you have already called MPINT_Init.
*	You may pass also SAPI5-format setting string (<voice name="saga"/><rate absspeed="-2">),
*	it is recognized from starting character <.
*
*	pSettingsStr	-> String containing synthesizer's settings
*
*	Returns: 0=Ok, MPINT_ERR_xxx=Failed and no message shown
*/
MPINTAPI MPINT_UseSettings( const char *pSettingsStr );
typedef long (*MPINT_UseSettingsType)(const char *);	// Type for function ptr

/*
*	Called once to uninitialize the synthesizer. NOTE! All other functions must be inactive before
*	calling this. If global voice cache's lock count reaches zero,
*	it will be deleted.
*	Locks internal Windows-like critical section during the call
*
*	pSettingsStr	-> String where to save settings, NULL=Do not save
*	nSettingsLen	-> Length of previous, recommended min length is 512 chars
*
*	Returns: 0=Ok
*/
MPINTAPI MPINT_Exit( char *pSettingsStr, int nSettingsLen );
typedef long (*MPINT_ExitType)(char *, int);	// Type for function ptr

/*
*	Synchronous call to speak given text to file. This may be called from any thread.
*	Voice parameters change synthesizer settings just for one call.
*
*	pText			-> Text
*	pFileName	-> Where WAV file will be saved
*	pReserved	-> For future extensions, use NULL
*						(MPINT_SpeakFileParams *) if not NULL
*
*	Returns: 0=Ok, Others=Failed AND NO MESSAGE SHOWN, in practise only reason for failing is writing destination file
*/
MPINTAPI MPINT_SpeakFile( const char *pText, const char *pFileName, void *pReserved );
typedef long (*MPINT_SpeakFileType)(const char *, const char *, void *);	// Type for function ptr


// Functions that have global synthesizer settings set by MPINT_UseSettings
/////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
// Functions that maintain speech parameters per instance/channel
// You may use this or previous function set or mix them as you wish.
// Channel "handle" values are not checked. Illegal value will likely
// crash your program. NULL values are checked and they return MPINT_ERR_EINVAL.
// FEW THREADING RULES:
// 1. All functions must be called from same one thread
// 2. Functions are not re-entrant
// 3. You may have many channels each running their own thread

/*
*	Initializes one channel. Adds reference count for global voice cache and calls
*	MPINT_InitEx if not called before. Release the channel by call to MPINT_ChannelExit.
*	Locks internal Windows-like critical section during the call
*
*	ppChannel		-> Channel "handle" will be saved here (actually pointer to created object). Never NULL if successful
*	pKey				-> Auhtorization string, obtain one from Timehouse Oy
*	pSettingsStr	-> String containing synthesizer's settings for this channel, ""=Use defaults
*	pReserved		-> For future use, use NULL
*
*	Returns: 0=Ok, MPINT_ERR_xxx=Failed and no message shown
*/
MPINTAPI MPINT_ChannelInitEx( void **ppChannel, const char *pKey, const char *pSettingsStr, void *pReserved );
typedef long (*MPINT_ChannelInitExType)(void **, const char *, const char *, void *);	// Type for function ptr

/*
*	Uses given settings. Use this to change settings if you have already called MPINT_Init.
*	You may pass also SAPI5-format setting string (<voice name="saga"/><rate absspeed="-2">),
*	it is recognized from starting character <.
*
*	pChannel			-> Handle from MPINT_ChannelInitEx-call
*	pSettingsStr	-> String containing synthesizer's settings
*
*	Returns: 0=Ok, MPINT_ERR_xxx=Failed and no message shown
*/
MPINTAPI MPINT_ChannelUseSettings( void *pChannel, const char *pSettingsStr );
typedef long (*MPINT_ChannelUseSettingsType)(void *, const char *);	// Type for function ptr

/*
*	Called once to uninitialize the synthesizer. If global voice cache's lock count reaches zero,
*	it will be deleted.
*	Locks internal Windows-like critical section during the call
*
*	pChannel			-> Handle from MPINT_ChannelInitEx-call, You may not use this handle any more!
*	pSettingsStr	-> String where to save settings, NULL=Do not save
*	nSettingsLen	-> Length of previous, recommended min length is 512 chars
*
*	Returns: 0=Ok
*/
MPINTAPI MPINT_ChannelExit( void *pChannel, char *pSettingsStr, int nSettingsLen );
typedef long (*MPINT_ChannelExitType)(void *, char *, int);	// Type for function ptr

/*
*	Synchronous call to speak given text to file. This may be called from any thread.
*	Voice parameters change synthesizer settings just for one call.
*
*	pChannel			-> Handle from MPINT_ChannelInitEx-call
*	pText			-> Text
*	pFileName	-> Where WAV file will be saved
*	pReserved	-> For future extensions, use NULL
*						(MPINT_SpeakFileParams *) if not NULL
*
*	Returns: 0=Ok, Others=Failed AND NO MESSAGE SHOWN, in practise only reason for failing is writing destination file
*/
MPINTAPI MPINT_ChannelSpeakFile( void *pChannel, const char *pText, const char *pFileName, void *pReserved );
typedef long (*MPINT_ChannelSpeakFileType)(void *, const char *, const char *, void *);	// Type for function ptr

// Functions that maintain speech parameters per instance/channel
/////////////////////////////////////////////////////////////////////////////



#ifdef _WIN32

/*
*	Unsupported and only for Windows.
*	Runs synthesizer's settings dialog with DialogBox-function.
*	You can use this to generate desired settings string.
*
*	hWndParent		-> Owner of the settings dialog
*	pSettingsStr	-> String where to save settings, NULL=Do not save
*	nSettingsLen	-> Length of previous, recommended min length is 512 chars
*
*	Returns: 0=Ok, ERROR_CANCELLED=User canceled, others=Error and message shown
*/
MPINTAPI MPINT_RunSettingsDlg( HWND hWndParent, char *pSettingsStr, int nSettingsLen );

// Unsupported and only for Windows.
// nFlags=CTulkTyo::FLAGS_xxx
int MPINT_Speak( const char *pText, int nFlags, HWND hWndNotifyReady, UINT uNotifyReadyMsg, LPARAM lNotifyData );

// Unsupported and only for Windows.
int MPINT_Stop();

#endif	// _WIN32

#endif
