/*
  +----------------------------------------------------------------------+
  | PHP Version 7                                                        |
  +----------------------------------------------------------------------+
  | Copyright (c) 1997-2017 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP license,      |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Author:                                                              |
  +----------------------------------------------------------------------+
*/

/* $Id$ */

#ifndef PHP_TTS_H
#define PHP_TTS_H

extern zend_module_entry tts_module_entry;
#define phpext_tts_ptr &tts_module_entry

#define PHP_TTS_VERSION "0.1.0" /* Replace with version number for your extension */

#ifdef PHP_WIN32
#	define PHP_TTS_API __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
#	define PHP_TTS_API __attribute__ ((visibility("default")))
#else
#	define PHP_TTS_API
#endif

#ifdef ZTS
#include "TSRM.h"
#endif

/*
  	Declare any global variables you may need between the BEGIN
	and END macros here:

ZEND_BEGIN_MODULE_GLOBALS(tts)
	zend_long  global_value;
	char *global_string;
ZEND_END_MODULE_GLOBALS(tts)
*/

/* Always refer to the globals in your function as TTS_G(variable).
   You are encouraged to rename these macros something shorter, see
   examples in any other php module directory.
*/
#define TTS_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(tts, v)

#if defined(ZTS) && defined(COMPILE_DL_TTS)
ZEND_TSRMLS_CACHE_EXTERN()
#endif

#endif	/* PHP_TTS_H */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include "tts_includes/qtts.h"
#include "tts_includes/msp_cmn.h"
#include "tts_includes/msp_errors.h"


/* wav音频头部格式 */
typedef struct _wave_pcm_hdr
{
	char            riff[4];                // = "RIFF"
	int		size_8;                 // = FileSize - 8
	char            wave[4];                // = "WAVE"
	char            fmt[4];                 // = "fmt "
	int		fmt_size;		// = 下一个结构体的大小 : 16

	short int       format_tag;             // = PCM : 1
	short int       channels;               // = 通道数 : 1
	int		samples_per_sec;        // = 采样率 : 8000 | 6000 | 11025 | 16000
	int		avg_bytes_per_sec;      // = 每秒字节数 : samples_per_sec * bits_per_sample / 8
	short int       block_align;            // = 每采样点字节数 : wBitsPerSample / 8
	short int       bits_per_sample;        // = 量化比特数: 8 | 16

	char            data[4];                // = "data";
	int		data_size;              // = 纯数据长度 : FileSize - 44 
} wave_pcm_hdr;

/* 默认wav音频头部数据 */
wave_pcm_hdr default_wav_hdr = 
{
	{ 'R', 'I', 'F', 'F' },
	0,
	{'W', 'A', 'V', 'E'},
	{'f', 'm', 't', ' '},
	16,
	1,
	1,
	16000,
	32000,
	2,
	16,
	{'d', 'a', 't', 'a'},
	0
};


/* 文本合成 */
int text_to_speech(const char* src_text, const char* des_path, const char* params)
{
  int          ret          = -1;
  FILE*        fp           = NULL;
  const char*  sessionID    = NULL;
  unsigned int audio_len    = 0;
  wave_pcm_hdr wav_hdr      = default_wav_hdr;
  int          synth_status = MSP_TTS_FLAG_STILL_HAVE_DATA;

  if (NULL == src_text || NULL == des_path)
    {
      return ret;
    }
  fp = fopen(des_path, "wb");
  if (NULL == fp)
    {
      return ret;
    }
  /* 开始合成 */
  sessionID = QTTSSessionBegin(params, &ret);
  if (MSP_SUCCESS != ret)
    {
      fclose(fp);
      return ret;
    }
  ret = QTTSTextPut(sessionID, src_text, (unsigned int)strlen(src_text), NULL);
  if (MSP_SUCCESS != ret)
    {
      QTTSSessionEnd(sessionID, "TextPutError");
      fclose(fp);
      return ret;
    }
  fwrite(&wav_hdr, sizeof(wav_hdr) ,1, fp); //添加wav音频头，使用采样率为16000
  while (1)
    {
      /* 获取合成音频 */
      const void* data = QTTSAudioGet(sessionID, &audio_len, &synth_status, &ret);
      if (MSP_SUCCESS != ret)
        break;
      if (NULL != data)
        {
          fwrite(data, audio_len, 1, fp);
          wav_hdr.data_size += audio_len; //计算data_size大小
        }
      if (MSP_TTS_FLAG_DATA_END == synth_status)
        break;
      usleep(150*1000); //防止频繁占用CPU
    }
  if (MSP_SUCCESS != ret)
    {
      QTTSSessionEnd(sessionID, "AudioGetError");
      fclose(fp);
      return ret;
    }
  /* 修正wav文件头数据的大小 */
  wav_hdr.size_8 += wav_hdr.data_size + (sizeof(wav_hdr) - 8);

  /* 将修正过的数据写回文件头部,音频文件为wav格式 */
  fseek(fp, 4, 0);
  fwrite(&wav_hdr.size_8,sizeof(wav_hdr.size_8), 1, fp); //写入size_8的值
  fseek(fp, 40, 0); //将文件指针偏移到存储data_size值的位置
  fwrite(&wav_hdr.data_size,sizeof(wav_hdr.data_size), 1, fp); //写入data_size的值
  fclose(fp);
  fp = NULL;
  /* 合成完毕 */
  ret = QTTSSessionEnd(sessionID, "Normal");

  return ret;
}


/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */
