/**

				HTK_WRITE.C
				Writes HTK format parameter files.

Copyright (C) 2009 Greg Kochanski, gpk@kochanski.org .

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

	**/
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "gpk_std.h"
#include "gpklib.h"
#include "gpklib/image.h"
#include "rw_misc.h"
#include "rbfile.h"
#include "internals.h"

#define D	if(1)

C unsigned int BYTEMASK = 0377;
C unsigned int CHAR_BITS = 8;
/* SWAP is correct for x86 architecture, not tested on others. */
C int SWAP = FALSE;

static BOOL write_int_2(FILE *fp, int p, BOOL swap)
{
 unsigned char c[2];
 assert(p);
 C int msb = swap ? 1: 0;
 c[1-msb] = (unsigned)p & BYTEMASK;
 c[msb] = ((unsigned)p>>CHAR_BITS) & BYTEMASK;
 return fwrite(c, 1, 2, fp)==2;
}


BOOL write_long_4(FILE *fp, long p, BOOL swap)
{
 unsigned char c[4];
 assert(p);
 int b, i;
 C int delta = swap ? 1 : -1;
 for(i=0,b=swap?0:3; i<4; i++, b+=delta, p>>=CHAR_BITS) {
	c[b] = p & BYTEMASK;
 }
 return fwrite(c, 1, 4, fp)==4;
}

union f32 { int32_t i; float f;};

BOOL write_float_4(FILE *fp, float p, BOOL swap)
{
 unsigned char c[4];
 f32 px;
 assert(sizeof(px.i) == sizeof(px.f));
 assert(sizeof(px) == sizeof(float));
 px.f = p;
 C int delta = swap ? -1 : 1;
 int i, b = swap ? 3 : 0;
 for(i=0,b=swap?3:0; i<4; i++, b+=delta, px.i>>=CHAR_BITS) {
	c[b] = px.i & BYTEMASK;
 }
 return fwrite((void *)c, sizeof(f32), 1, fp)==1;
}


#define NParmKind 12
static C char *paramKindName[NParmKind] = {"WAVEFORM", "LPC",
	"LPCREFC", "LPCEPSTRA", "LPDELCEP", "IREFC",
	"MFCC", "FBANK", "MELSPEC", "USER", "DISCRETE", "PLP"
	};
static C char pQual[] = {'E', 'N', 'D', 'A', 'C', 'Z', 'K', 'O', '\0'};


LOCAL int pK_from_name(C char *bname, C char *qname)
{
 int i, pK = -1;
 if(!bname)
	return pK;
 for(i=0; i<NParmKind; i++)
	if(strcmp(paramKindName[i], bname) == 0)
		pK = i;
 C int x = 0100;
 if(!qname)
	return pK;
 C char *q = qname;
 while(*q) {
	while(*q == '_')
		q++;
	for(i=0; pQual[i]!='\0'; i++) {
		if(pQual[i] == *q)
			pK |= (x<<i);
	}
	q++;
 }
 return pK;
}


LOCAL BOOL print_properties(FILE *out, long nSamples, double dt, int sampSize, int parmKind)
{
 C long sampPeriod = roundL(dt*1e7);
 return write_long_4(out, nSamples, SWAP) &&
	write_long_4(out, sampPeriod, SWAP) &&
	write_int_2(out, sampSize, SWAP) &&
	write_int_2(out, parmKind, SWAP);
}


LOCAL void get_scalings(C struct image *p, double bitpix, double *bscale, double *bzero)
{
	assert(bitpix == -32);
	*bscale = p->zscale;
	*bzero = -p->zshift/p->zscale;
}


BOOL HTK_writefile(C struct image *p, FILE *out, C proplist& control)
{
 assert(p);
 assert(out);
 assert(p->prop);
 proplist q(*p->prop);
 normalize_proplist(&q, p);
 q += control;
 C int bitpix = -32;

 double bscale, bzero;
 get_scalings(p, bitpix, &bscale, &bzero);

 int parmKind = p->prop->getd("parmKind", -1);
 if(parmKind == -1)
	parmKind = pK_from_name(p->prop->gets("BParmKind", (C char *)0),
				p->prop->gets("QParmKind", (C char *)0));
 if(parmKind == -1)
	parmKind = pK_from_name("USER", "");

 print_properties(out, p->nlines, p->yscale, p->npts*(abs(bitpix)/CHAR_BITS),
			parmKind);
 return write_out_data(out, p, bitpix,
			SWAP ? ANTI_NETWORK: NETWORK_ORDER,
			bscale, bzero);
}
