%{
/*
 * SFZ file reader, Greg Lee, 10/04.
 * Adapted from Cfg file reader, Greg Lee, 8/93.
 * Adapted from Adagio for KMidi 12/99.
 *	$Id: cfg.l,v 1.8 2000/08/08 17:32:37 faure Exp $
 */
/*
 Also adapted from:

    Wav2pat -- simple WAVE to GUS patch converter
    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>

    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.

    This is a little tool to convert RIFF WAVEs to GUS-compatible
    patches. A WAVE is read from stdin, and a GUS patch is written to
    stdout.

*/
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "gtim.h"
#ifdef HAVE_OGG
#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>
#endif
#include "common.h"
#include "instrum.h"
#include "playmidi.h"
#include "readmidi.h"
#include "output.h"
#include "controls.h"
#include "tables.h"

#define YY_ALWAYS_INTERACTIVE 0
#define YY_NEVER_INTERACTIVE 1

#define YY_INPUT(buf,result,max_size) \
	 result = fread( buf, 1, max_size, yyin );

static char *sfzname = 0;

static int rcf_count=1;

#define MAX_INCLUDE_DEPTH 40
static YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
static int include_stack_ptr = 0;
static char *this_fname[MAX_INCLUDE_DEPTH] = { NULL };
static int this_line[MAX_INCLUDE_DEPTH] = { 0 };

static int read_sample(char *name);
#ifndef LOADER
static void make_pat(void);
#endif
static void point_regions_to_groups(void);
static void leave_region(void);
static int enter_region(void);
static void leave_group(void);
static int enter_group(void);

#ifndef LOADER
typedef union {
      unsigned char c[4];
      unsigned long l;
} long_end;
typedef union {
      unsigned char c[2];
      unsigned short s;
} short_end;

typedef struct linfo {
	unsigned char velmin;
	unsigned char velmax;
	unsigned char left_samples;
	unsigned char right_samples;
} linfo;

#pragma pack (1)

struct pat_header
  {
    char            magic[12];
    char            version[10];
    char            description[60];
    unsigned char   instruments;
    unsigned char   pat_voices;
    unsigned char   pat_channels;
    unsigned short  nr_waveforms;
    unsigned short  master_volume;
    unsigned long   data_size;
    char	    sf2magic[7];
    char	    unused1[29];
    short	    instrument_number;
    char	    instrument_name[16];
    int		    instrument_size;
    unsigned char   layer_count;
    unsigned char   velocity_count;
    struct linfo    sf2layer[9];
    char	    unused2[40-37];
    char	    layer_duplicate;
    char	    layer_number;
    int		    layer_size;
    unsigned char   num_samples;
    struct linfo    sf2layer2[10];
  };

#pragma pack (1)

struct sample_header
  {
    char            name[7];
    unsigned char   fractions;
    long            len;
    long            loop_start;
    long            loop_end;
    unsigned short  base_freq;
    long            low_note;
    long            high_note;
    long            base_note;
    short           detune;
    unsigned char   panning;

    unsigned char   envelope_rate[6];
    unsigned char   envelope_offset[6];

    unsigned char   tremolo_sweep;
    unsigned char   tremolo_rate;
    unsigned char   tremolo_depth;

    unsigned char   vibrato_sweep;
    unsigned char   vibrato_rate;
    unsigned char   vibrato_depth;

    char            modes;

    short           scale_frequency;
    unsigned short  scale_factor;
    unsigned short  volume; /* Is this really here?? */

    unsigned char   volume_envelope_delay;
    unsigned char   exclusive_class;
    unsigned char   vibrato_delay;

    unsigned char   mod_envelope_rate[6];
    unsigned char   mod_envelope_offset[6];
    unsigned char   mod_envelope_delay;
    unsigned char   chorus_effect;
    unsigned char   reverb_effect;
    short	    resonance;
    short	    cutoff_frequency;
    unsigned char   modEnvToPitch;
    unsigned char   modEnvToFilterFc;
    unsigned char   modLfoToFilterFc;
    unsigned char   keynumToModEnvHold;
    unsigned char   keynumToModEnvDecay;
    unsigned char   keynumToVolEnvHold;
    unsigned char   keynumToVolEnvDecay;
    unsigned char   true_panning;

    short	    lfo_rate;
    unsigned char   lfo_depth;
    char	    aps_parameter;
  };
#endif

#define TRUE	1
#define FALSE	0

#define REGION_IN_GROUP 0
#define REGION_IS_BUSY  1

#define FIRST_SFZ_PARM 11
#define KEY	11
#define HIKEY	12
#define LOKEY	13
#define PITCH_KEYCENTER 14
#define OFFSET	15
#define END	16
#define LOOP_START  17
#define LOOP_END    18
#define HIVEL	19
#define LOVEL	20
#define GROUP	21
#define OFF_BY	22
#define TRIGGER	23
  #define VAL_TRIGGER_ATTACK	0
  #define VAL_TRIGGER_FIRST	1
  #define VAL_TRIGGER_RELEASE	2
  #define VAL_TRIGGER_LEGATO	3
#define LOOP_MODE	24
  #define VAL_LOOP_SUSTAIN	1
#define SW_HIKEY	25
#define SW_LOKEY	26
#define SW_UP		27
#define SW_DOWN		28
#define SW_LAST		29
#define MAX_SFZ_PARM	30

#define AMPEG_RELEASE	1
#define VOLUME		2
#define AMP_RANDOM	3
#define HIRAND		4
#define LORAND		5
#define MAX_FLOAT_PARM	6

#define MAX_SFZ_REGION 2048
#define MAX_SFZ_GROUP 128


static int m;

static int am_in_group = FALSE;
static int am_in_region = FALSE;
static int am_in_group_scope = FALSE;

static int32 default_parm[MAX_SFZ_PARM] = {
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* key */	60,
/* hikey */	60,
/* lokey */	60,
/* pitch_keycenter */	60,
/* offset */	0,
/* end */	0,
/* loop_start */	0,
/* loop_end */	0,
/* hivel */	127,
/* lovel */	9,
/* group */	0,
/* off_by */	0,
/* trigger */	0,
/* loop_mode */	0,
/* sw_hikey */	127,
/* sw_lokey */	0,
/* sw_up */	-1,
/* sw_down */	-1,
/* sw_last */	-1
};
static double default_flt_parm[MAX_FLOAT_PARM] = {
		    0,
/* ampeg_release */ 0,
/* volume */	    0,
/* amp_random */    0,
/* hirand */        1,
/* lorand */        0
};

static int32 group_parm[MAX_SFZ_PARM];
static int32 region_parm[MAX_SFZ_PARM];
static double group_flt_parm[MAX_FLOAT_PARM];
static double region_flt_parm[MAX_FLOAT_PARM];
static int32 region[MAX_SFZ_REGION][MAX_SFZ_PARM];
static double region_flt[MAX_SFZ_REGION][MAX_FLOAT_PARM];
static int32 current_region = 0;
static int32 current_group = 0;

static unsigned char *region_left_sample[MAX_SFZ_REGION] = { NULL };
static unsigned char *region_right_sample[MAX_SFZ_REGION] = { NULL };
static int32 region_datasize[MAX_SFZ_REGION];
static int32 region_channels[MAX_SFZ_REGION];
static int32 region_modes[MAX_SFZ_REGION];
static int32 region_samplerate[MAX_SFZ_REGION];
static int32 region_samplesize[MAX_SFZ_REGION];

#ifdef LOADER
#define SFZERR ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
#define SFZNOTE ctl->cmsg (CMSG_INFO, VERB_VERBOSE,
#define SFZDBG ctl->cmsg (CMSG_INFO, VERB_DEBUG,
#define SFZNL
#else
static int32 verbosity=0;
#define SFZERR fprintf(stderr,
#define SFZNOTE if (verbosity) fprintf(stderr,
#define SFZDBG if (verbosity) fprintf(stderr,
#define SFZNL  if (verbosity) fprintf(stderr,"\n");
#endif

#define GROUP_IS_FREE -1

static int32
    group_link[MAX_SFZ_GROUP],
    sample_left_datasize[MAX_SFZ_GROUP],
    sample_right_datasize[MAX_SFZ_GROUP],
    sample_channels[MAX_SFZ_GROUP],
    sample_modes[MAX_SFZ_GROUP],
    sample_samplerate[MAX_SFZ_GROUP],
    sample_samplesize[MAX_SFZ_GROUP];

static unsigned char
    *sample_left_buf[MAX_SFZ_GROUP] = { NULL},
    *sample_right_buf[MAX_SFZ_GROUP] = { NULL};

static int ipn_val(char *text);

%}

%option noyywrap
%option nounput
%option outfile = "sfz2pat.c"

nm	([^\n]+".wav"|[^ \t\n\r]+|\"[^\"\n]+\")
ipn	[A-Ga-g][#b]?([0-9]|"-1")

%s	K

%%

"//".*	;

<K>"<group>"	{
	int i;
	leave_region();
	leave_group();
	if (!enter_group()) {
		SFZERR
		"Can't start group\n");
		return 1;
	}
	am_in_group_scope = TRUE;
	for (i = FIRST_SFZ_PARM; i < MAX_SFZ_PARM; i++) group_parm[i] = default_parm[i];
	for (i = 0; i < MAX_FLOAT_PARM; i++) group_flt_parm[i] = default_flt_parm[i];
	group_parm[REGION_IN_GROUP] = current_group;
	BEGIN(0);
}
<K>"<region>"	{
	int i;
	if (!am_in_group) {
		SFZERR
		"Can't start region outside group.\n");
		return 1;
	}
	leave_region();
	if (!enter_region()) {
		SFZERR
		"Can't start region\n");
		return 1;
	}
	am_in_group_scope = FALSE;
	for (i = 0; i < MAX_SFZ_PARM; i++) region_parm[i] = group_parm[i];
	for (i = 0; i < MAX_FLOAT_PARM; i++) region_flt_parm[i] = group_flt_parm[i];
	BEGIN(0);
}
<K>"sample="{nm} {
	int i = 7, j;
	unsigned namelen;
	if (yytext[i] == '"') {
		i++;
		for (j = i; j < yyleng && yytext[j] != '"'; j++) ;
	}
	else j = yyleng;
	namelen = (unsigned)(j - i + 1);
	sfzname = strncpy( (char *)malloc(namelen), yytext+i, (unsigned)(j-i) );
	sfzname[j-i] = '\0';
	for (i = 0; i < (int)namelen; i++) if (sfzname[i] == '\\') sfzname[i] = '/';
	SFZDBG
	"Sample name is \"%s\"", sfzname);
	SFZNL
	if (read_sample(sfzname)) {
#ifndef LOADER
		fprintf(stderr, "\n");
#endif
		return 0;
	}
	BEGIN(0);
}
<K>"hivel="[0-9]+ {
	m = atoi(yytext+6);
	if (am_in_group_scope) group_parm[HIVEL] = m;
	else region_parm[HIVEL] = m;
	BEGIN(0);
}
<K>"lovel="[0-9]+ {
	m = atoi(yytext+6);
	if (am_in_group_scope) group_parm[LOVEL] = m;
	else region_parm[LOVEL] = m;
	BEGIN(0);
}
<K>"group="[0-9]+ {
	m = atoi(yytext+6);
	if (am_in_group_scope) group_parm[GROUP] = m;
	else region_parm[GROUP] = m;
	BEGIN(0);
}
<K>"off_by="[0-9]+ {
	m = atoi(yytext+7);
	if (am_in_group_scope) group_parm[OFF_BY] = m;
	else region_parm[OFF_BY] = m;
	BEGIN(0);
}
<K>"trigger=attack" {
	if (am_in_group_scope) group_parm[TRIGGER] = VAL_TRIGGER_ATTACK;
	else region_parm[TRIGGER] = VAL_TRIGGER_ATTACK;
	BEGIN(0);
}
<K>"trigger=release" {
	if (am_in_group_scope) group_parm[TRIGGER] = VAL_TRIGGER_RELEASE;
	else region_parm[TRIGGER] = VAL_TRIGGER_RELEASE;
	BEGIN(0);
}
<K>"trigger=legato" {
	if (am_in_group_scope) group_parm[TRIGGER] = VAL_TRIGGER_LEGATO;
	else region_parm[TRIGGER] = VAL_TRIGGER_LEGATO;
	BEGIN(0);
}
<K>"trigger=first" {
	if (am_in_group_scope) group_parm[TRIGGER] = VAL_TRIGGER_FIRST;
	else region_parm[TRIGGER] = VAL_TRIGGER_FIRST;
	BEGIN(0);
}
<K>"loop_mode=loop_sustain" {
	if (am_in_group_scope) group_parm[LOOP_MODE] = VAL_LOOP_SUSTAIN;
	else region_parm[LOOP_MODE] = VAL_LOOP_SUSTAIN;
	BEGIN(0);
}
<K>"ampeg_release="[0-9]+("."[0-9]*)? {
	double d;
	d = atof(yytext+14);
	if (am_in_group_scope) group_flt_parm[AMPEG_RELEASE] = d;
	else region_flt_parm[AMPEG_RELEASE] = d;
	BEGIN(0);
}
<K>"volume="("+"|"-")?[0-9]+("."[0-9]*)? {
	double d;
	d = atof(yytext+7);
	if (am_in_group_scope) group_flt_parm[VOLUME] = d;
	else region_flt_parm[VOLUME] = d;
	BEGIN(0);
}
<K>"amp_random="[0-9]+("."[0-9]*)? {
	double d;
	d = atof(yytext+11);
	if (am_in_group_scope) group_flt_parm[AMP_RANDOM] = d;
	else region_flt_parm[AMP_RANDOM] = d;
	BEGIN(0);
}
<K>"hirand="[0-9]+("."[0-9]*)? {
	double d;
	d = atof(yytext+7);
	if (am_in_group_scope) group_flt_parm[HIRAND] = d;
	else region_flt_parm[HIRAND] = d;
	BEGIN(0);
}
<K>"lorand="[0-9]+("."[0-9]*)? {
	double d;
	d = atof(yytext+7);
	if (am_in_group_scope) group_flt_parm[LORAND] = d;
	else region_flt_parm[LORAND] = d;
	BEGIN(0);
}
<K>"hikey="[0-9]+ {
	m = atoi(yytext+6);
	if (am_in_group_scope) group_parm[HIKEY] = m;
	else region_parm[HIKEY] = m;
	BEGIN(0);
}
<K>"lokey="[0-9]+ {
	m = atoi(yytext+6);
	if (am_in_group_scope) group_parm[LOKEY] = m;
	else region_parm[LOKEY] = m;
	BEGIN(0);
}
<K>"pitch_keycenter="[0-9]+ {
	m = atoi(yytext+16);
	if (am_in_group_scope) group_parm[PITCH_KEYCENTER] = m;
	else region_parm[PITCH_KEYCENTER] = m;
	BEGIN(0);
}
<K>"key="[0-9]+ {
	m = atoi(yytext+4);
	if (am_in_group_scope) group_parm[KEY] =
		group_parm[HIKEY] = 
		group_parm[LOKEY] = 
		group_parm[PITCH_KEYCENTER] = m;
	else region_parm[KEY] =
		region_parm[HIKEY] = 
		region_parm[LOKEY] = 
		region_parm[PITCH_KEYCENTER] = m;
	BEGIN(0);
}
<K>"key="{ipn} {
	m = ipn_val(yytext);
	if (am_in_group_scope) group_parm[KEY] =
		group_parm[HIKEY] = 
		group_parm[LOKEY] = 
		group_parm[PITCH_KEYCENTER] = m;
	else region_parm[KEY] =
		region_parm[HIKEY] = 
		region_parm[LOKEY] = 
		region_parm[PITCH_KEYCENTER] = m;
	BEGIN(0);
/*
C4 is middle C = midi note 60

-1 00 01 02 03 04 05 06 07 08 09 10 11
0  12 13 14 15 16 17 18 19 20 21 22 23
1  24 25 26 27 28 29 30 31 32 33 34 35
2  36 37 38 39 40 41 42 43 44 45 46 47
3  48 49 50 51 52 53 54 55 56 57 58 59
4  60 61 62 63 64 65 66 67 68 69 70 71
   C  C# D  D# E  F  F# G  G# A  A# B
5  72 73 74 75 76 77 78 79 80 81 82 83
6  84 85 86 87 88 89 90 91 92 93 94 95
7  96 97 98 99 00 01 02 03 04 05 06 07
8  08 09 10 11 12 13 14 15 16 17 18 19
9  20 21 22 23 24 25 26 27
*/
}
<K>"hikey="{ipn} {
	m = ipn_val(yytext);
	if (am_in_group_scope) group_parm[HIKEY] = m;
	else region_parm[HIKEY] = m;
	BEGIN(0);
}
<K>"lokey="{ipn} {
	m = ipn_val(yytext);
	if (am_in_group_scope) group_parm[LOKEY] = m;
	else region_parm[LOKEY] = m;
	BEGIN(0);
}
<K>"pitch_keycenter="{ipn} {
	m = ipn_val(yytext);
	if (am_in_group_scope) group_parm[PITCH_KEYCENTER] = m;
	else region_parm[PITCH_KEYCENTER] = m;
	BEGIN(0);
}
<K>"sw_hikey="[0-9]+ {
	m = atoi(yytext+9);
	if (am_in_group_scope) group_parm[SW_HIKEY] = m;
	else region_parm[SW_HIKEY] = m;
	BEGIN(0);
}
<K>"sw_hikey="{ipn} {
	m = ipn_val(yytext);
	if (am_in_group_scope) group_parm[SW_HIKEY] = m;
	else region_parm[SW_HIKEY] = m;
	BEGIN(0);
}
<K>"sw_lokey="[0-9]+ {
	m = atoi(yytext+9);
	if (am_in_group_scope) group_parm[SW_LOKEY] = m;
	else region_parm[SW_LOKEY] = m;
	BEGIN(0);
}
<K>"sw_lokey="{ipn} {
	m = ipn_val(yytext);
	if (am_in_group_scope) group_parm[SW_LOKEY] = m;
	else region_parm[SW_LOKEY] = m;
	BEGIN(0);
}
<K>"sw_up="[0-9]+ {
	m = atoi(yytext+6);
	if (am_in_group_scope) group_parm[SW_UP] = m;
	else region_parm[SW_UP] = m;
	BEGIN(0);
}
<K>"sw_up="{ipn} {
	m = ipn_val(yytext);
	if (am_in_group_scope) group_parm[SW_UP] = m;
	else region_parm[SW_UP] = m;
	BEGIN(0);
}
<K>"sw_down="[0-9]+ {
	m = atoi(yytext+8);
	if (am_in_group_scope) group_parm[SW_DOWN] = m;
	else region_parm[SW_DOWN] = m;
	BEGIN(0);
}
<K>"sw_down="{ipn} {
	m = ipn_val(yytext);
	if (am_in_group_scope) group_parm[SW_DOWN] = m;
	else region_parm[SW_DOWN] = m;
	BEGIN(0);
}
<K>"sw_last="[0-9]+ {
	m = atoi(yytext+8);
	if (am_in_group_scope) group_parm[SW_LAST] = m;
	else region_parm[SW_LAST] = m;
	BEGIN(0);
}
<K>"sw_last="{ipn} {
	m = ipn_val(yytext);
	if (am_in_group_scope) group_parm[SW_LAST] = m;
	else region_parm[SW_LAST] = m;
	BEGIN(0);
}

<K>"offset="[0-9]+ {
	m = atoi(yytext+7);
	if (am_in_group_scope) group_parm[OFFSET] = m;
	else region_parm[OFFSET] = m;
	BEGIN(0);
}

<K>"end="[0-9]+ {
	m = atoi(yytext+4);
	if (am_in_group_scope) group_parm[END] = m;
	else region_parm[END] = m;
	BEGIN(0);
}

<K>"loop_start="[0-9]+ {
	m = atoi(yytext+11);
	if (am_in_group_scope) group_parm[LOOP_START] = m;
	else region_parm[LOOP_START] = m;
	BEGIN(0);
}

<K>"loop_end="[0-9]+ {
	m = atoi(yytext+9);
	if (am_in_group_scope) group_parm[LOOP_END] = m;
	else region_parm[LOOP_END] = m;
	BEGIN(0);
}

<K>"source"[ \t]+{nm} {
	char *fname;
	int i = 0;
	FILE *save_yyin;

	while (isspace(yytext[i])) i++;
	i += 6;
	while (isspace(yytext[i])) i++;


        if ( include_stack_ptr >= MAX_INCLUDE_DEPTH ) {
		SFZERR
		 "Probable source loop in configuration files\n");
		return (-1);
        }
        include_stack[include_stack_ptr++] =
                YY_CURRENT_BUFFER;

	fname = strcpy( (char *)malloc(strlen(yytext+i)+1), yytext+i );
	if (this_fname[include_stack_ptr]) free(this_fname[include_stack_ptr]);
	this_fname[include_stack_ptr] = strdup(fname);

	save_yyin = yyin;
	yyin = NULL;

#ifdef LOADER
	yyin = open_file (fname, 1, OF_NORMAL, 0);
#else
	yyin = fopen(fname, "r");
#endif
	if (yyin == NULL) {
		SFZERR
		 "Source file %s not found\n", fname);
		include_stack_ptr--;
	}

	if (yyin == NULL) yyin = save_yyin;
	else {
	    rcf_count++;
            yy_switch_to_buffer(
                yy_create_buffer( yyin, YY_BUF_SIZE ) );
	}
	BEGIN(0);
}  

<<EOF>> {
        if ( --include_stack_ptr < 0 ) {
                yyterminate();
        }
        else {
		if (yyin) fclose(yyin);
                yy_delete_buffer( YY_CURRENT_BUFFER );
		rcf_count--;
                yy_switch_to_buffer(
                     include_stack[include_stack_ptr] );
        }
	BEGIN(K);
}

[ \t]+	{
	BEGIN(K);
}

\n	{
	this_line[include_stack_ptr]++;
	BEGIN(K);
}
.	;

%%

static int
ipn_val(char *text)
{
	int i, sharp = 0, octave;
	char keyletter;

	for (i = 0; text[i] != '='; i++);
	i++;
	keyletter = text[i++];

	if (text[i] == '#') sharp = 1;
	else if (text[i] == 'b') sharp = -1;
	else i--;
	i++;

	if (text[i] == '-') octave = 0;
	else octave = 12 *(text[i] - '0' + 1);
	switch(keyletter) {
		case 'c':
		case 'C': break;
		case 'd':
		case 'D': octave += 2; break;
		case 'e':
		case 'E': octave += 4; break;
		case 'f':
		case 'F': octave += 5; break;
		case 'g':
		case 'G': octave += 7; break;
		case 'a':
		case 'A': octave += 9; break;
		case 'b':
		case 'B': octave += 11; break;
	}
	return (octave + sharp);
}

static int sfz_is_ready = FALSE;
static int first_group = -1;
static int previous_group = -1;

static void
initialize_sfz(void)
{
	int i;
	first_group = previous_group = -1;
	am_in_group = am_in_region = am_in_group_scope = FALSE;
	if (sfz_is_ready) return;
	for (i = 0; i < MAX_SFZ_GROUP; i++) {
		group_link[i] = GROUP_IS_FREE;
		sample_left_buf[i] = NULL;
		sample_right_buf[i] = NULL;
	}
	for (i = 0; i < MAX_SFZ_REGION; i++) {
		region_left_sample[i] = NULL;
		region_right_sample[i] = NULL;
		region[i][REGION_IN_GROUP] = -1;
		region[i][REGION_IS_BUSY] = FALSE;
	}
	sfz_is_ready = TRUE;
}
#ifndef LOADER

static int big_endian = 1;

#if 0
static long longnum(unsigned char c1, unsigned char c2,
		unsigned char c3, unsigned char c4)
{
    long_end lswitch;
    if (big_endian) {
	lswitch.c[0] = c4;
	lswitch.c[1] = c3;
	lswitch.c[2] = c2;
	lswitch.c[3] = c1;
    } else {
	lswitch.c[0] = c1;
	lswitch.c[1] = c2;
	lswitch.c[2] = c3;
	lswitch.c[3] = c4;
    }
    return(lswitch.l);
}
#endif

static void numlong(long number, unsigned char* c)
{
    long_end lswitch;
    lswitch.l = number;
    if (big_endian) {
	c[3] = lswitch.c[0];
	c[2] = lswitch.c[1];
	c[1] = lswitch.c[2];
	c[0] = lswitch.c[3];
    } else {
	c[0] = lswitch.c[0];
	c[1] = lswitch.c[1];
	c[2] = lswitch.c[2];
	c[3] = lswitch.c[3];
    }
}

#if 0
static short shortnum(unsigned char c1, unsigned char c2)
{
    short_end sswitch;
    if (big_endian) {
	sswitch.c[0] = c2;
	sswitch.c[1] = c1;
    } else {
	sswitch.c[0] = c1;
	sswitch.c[1] = c2;
    }
    return(sswitch.s);
}
#endif

static void numshort(short number, unsigned char *c)
{
    short_end sswitch;
    sswitch.s = number;
    if (big_endian) {
	c[1] = sswitch.c[0];
	c[0] = sswitch.c[1];
    } else {
	c[0] = sswitch.c[0];
	c[1] = sswitch.c[1];
    }
}

static void byteorder()
{   long_end hexx;

    hexx.c[0] = 0x12;
    hexx.c[1] = 0x34;
    hexx.c[2] = 0x56;
    hexx.c[3] = 0x78;
    if (hexx.l == 0x78563412) big_endian = 0;
}


#define MAXSPV 14


static void fix_header_write(unsigned char *buf, struct pat_header *header)
{
	numshort(header->nr_waveforms, buf + 85);
	numshort(header->master_volume, buf + 87);
}

static void fix_sample_write(unsigned char *buf, struct sample_header *sample)
{
	numlong(sample->len, buf + 8);
	numlong(sample->loop_start, buf + 12);
	numlong(sample->loop_end, buf + 16);
	numshort(sample->base_freq, buf + 20);
	numlong(sample->low_note, buf + 22);
	numlong(sample->high_note, buf + 26);
	numlong(sample->base_note, buf + 30);
	numshort(sample->detune, buf + 34);
	buf[36] = sample->panning;
	memcpy(&buf[37], sample->envelope_rate, 6);
	memcpy(&buf[43], sample->envelope_offset, 6);
	buf[49] = sample->tremolo_sweep;
	buf[50] = sample->tremolo_rate;
	buf[51] = sample->tremolo_depth;
	buf[52] = sample->vibrato_sweep;
	buf[53] = sample->vibrato_rate;
	buf[54] = sample->vibrato_depth;
	buf[55] = sample->modes;
	numshort(sample->scale_frequency, buf + 56);
	numshort(sample->scale_factor, buf + 58);
	numshort(sample->volume, buf + 60);
	memcpy(&buf[65], sample->mod_envelope_rate, 6);
	memcpy(&buf[71], sample->mod_envelope_offset, 6);
	numshort(sample->resonance, buf + 79);
	numshort(sample->cutoff_frequency, buf + 81);
	numshort(sample->lfo_rate, buf + 92);
}

/* converts milliseconds to the even stranger floating point GUS format */
static int msec2gus(int t, int r)
{
   static int vexp[4] = { 1, 8, 64, 512 };
   int e, mantissa;

   if (r <= 0)
      return 0x3F;

   t = t * 32 / r;

   if (t <= 0)
      return 0x3F;

   for (e=3; e>=0; e--) {
      mantissa = (vexp[e] * 16 + t/2) / t;

      if ((mantissa > 0) && (mantissa < 64))
	 return ((e << 6) | mantissa);
   }

   return 0xC1;
}

static void nullify_extras ( struct sample_header *sample)
{	int i;

	sample->volume_envelope_delay = 0;
	sample->exclusive_class = 0;
	sample->vibrato_delay = 0;

	for (i = 0; i < 6; i++) sample->mod_envelope_rate[i] = 0;
	for (i = 0; i < 6; i++) sample->mod_envelope_offset[i] = 0;

	sample->mod_envelope_delay = 0;
	sample->chorus_effect = 0;
	sample->reverb_effect = 0;
	sample->resonance = 0;
	sample->cutoff_frequency = 0;
	sample->modEnvToPitch = 0;
	sample->modEnvToFilterFc = 0;
	sample->modLfoToFilterFc = 0;
	sample->keynumToModEnvHold = 0;
	sample->keynumToModEnvDecay = 0;
	sample->keynumToVolEnvHold = 0;
	sample->keynumToVolEnvDecay = 0;
	sample->true_panning = 0;
}

static void make_sample ( struct sample_header *sample, int r)
{
	uint32 volume = 255;
	uint32 sustain = 250;
	double attack = 0.1;
	double hold = 0.1;
	double decay = 0.1;
	double release = 0.1;
	//double delay = 0;

	if (region_flt[r][AMPEG_RELEASE] >0.0001)
		release = region_flt[r][AMPEG_RELEASE] * 1000;

	sample->envelope_rate[ATTACK] = msec2gus(attack, volume);
	sample->envelope_offset[ATTACK] = volume;

	sample->envelope_rate[HOLD] = msec2gus(hold, volume - 1);
	sample->envelope_offset[HOLD] = volume - 1;

	sample->envelope_rate[DECAY] = msec2gus(decay, volume - 1 - sustain);
	sample->envelope_offset[DECAY] = sustain;

	sample->envelope_rate[RELEASE] = msec2gus(release, 255);
	sample->envelope_offset[RELEASE] = 0;

	sample->envelope_rate[RELEASEB] = 63;
	sample->envelope_offset[RELEASEB] = 0;
	sample->envelope_rate[RELEASEC] = 63;
	sample->envelope_offset[RELEASEC] = 0;

	nullify_extras(sample);

	sample->modes |= MODES_ENVELOPE;

	if (region[r][LOOP_MODE] == VAL_LOOP_SUSTAIN) sample->modes |= (MODES_LOOPING|MODES_SUSTAIN);
}

#else

static void nullify_extras (Sample *sp)
{	int i;

	//sp->volume_envelope_delay = 0;
	//sp->vibrato_delay = 0;

	for (i = 0; i < 6; i++) sp->modulation_rate[i] = 0;
	for (i = 0; i < 6; i++) sp->modulation_offset[i] = 0;

	//sp->mod_envelope_delay = 0;
	sp->chorusdepth = 0;
	sp->reverberation = 0;
	sp->resonance = 0;
	sp->modEnvToPitch = 0;
	sp->modEnvToFilterFc = 0;
	sp->modLfoToFilterFc = 0;
	sp->keyToModEnvHold = 0;
	sp->keyToModEnvDecay = 0;
	sp->keyToVolEnvHold = 0;
	sp->keyToVolEnvDecay = 0;
	sp->lfo_sweep_increment =
			    sp->lfo_phase_increment = sp->lfo_depth = 0;
	sp->aps_parameter = 0;
	sp->vibrato_delay = 0;
}


/* convert from 8bit value to fractional offset (15.15) */
static uint32
to_offset (uint32 offset)
{
    if (offset > 255)
	return 255 << (7 + 15);
    return (uint32) offset << (7 + 15);
}

/* calculate ramp rate in fractional unit;
 * diff = 8bit, time = msec
 */
static uint32
calc_rate (uint32 diff, double msec)
{
    double  rate;

    if (!diff) return 10;
    diff <<= (7 + 15);
    if (msec * CONTROLS_PER_SECOND < (1000.0/255.0)) return (255 << (7 + 15));
    rate = ((double) diff * 1000.0) / (msec * CONTROLS_PER_SECOND);
    if (rate < 10.0)
	return 10;
    return (uint32) rate;
}


#define TO_VOLUME(decibel) pow(10.0, (double)(decibel)/20.0)
#define HOLD_EXCURSION 1
#define ENV_BOTTOM 0

static void make_sample(Sample *sp, ToneBank *b, int tn, int percussion, int r) {
    	int note_to_use = b->tone[tn].note;
	int amp = b->tone[tn].amp;
	int strip_loop = b->tone[tn].strip_loop;
	int strip_envelope = b->tone[tn].strip_envelope;
	int strip_tail = b->tone[tn].strip_tail;
	uint32 volume = 255;
	uint32 sustain = 250;
	double attack = 0.1;
	double hold = 0.1;
	double decay = 0.1;
	double release = 0.1;
	double delay = 0;
	double sfz_volume = region_flt[r][VOLUME];

	//if (note_to_use == -1 && percussion) note_to_use = tn;

	sp->sample_rate = region_samplerate[r];
	sp->low_freq = freq_table[region[r][LOKEY] ];
	sp->high_freq = freq_table[region[r][HIKEY] ];
	sp->root_freq = freq_table[region[r][PITCH_KEYCENTER] ];

	if (b->tone[tn].pan == -1) sp->panning = 64;
	else sp->panning = b->tone[tn].pan;

	if (b->tone[tn].tuning) {
	    double  tune_factor = (double) (b->tone[tn].tuning) / 1200.0;
	    tune_factor = pow (2.0, tune_factor);
	    sp->root_freq =
		(uint32) (tune_factor * (double) sp->root_freq);
	}

	sp->modes = region_modes[r];
	sp->tremolo_sweep_increment =
		sp->tremolo_phase_increment = sp->tremolo_depth = 0;
	sp->vibrato_sweep_increment =
		sp->vibrato_control_ratio = sp->vibrato_depth = 0;
	sp->freq_center = region[r][PITCH_KEYCENTER];
	sp->freq_scale = 1024;
	sp->attenuation = 0;

	sp->sw_hikey = (char)region[r][SW_HIKEY];
	sp->sw_lokey = (char)region[r][SW_LOKEY];
	sp->sw_up = (char)region[r][SW_UP];
	sp->sw_down = (char)region[r][SW_DOWN];
	sp->sw_last = (char)region[r][SW_LAST];

/* ?? */
	//if (!percussion) release = 400;
	//if (!percussion) decay = 400;
	if (percussion) {
		strip_envelope = 1;
	}
	else {
		release = 400;
		decay = 400;
	}

	if (region_flt[r][AMPEG_RELEASE] >0.0001)
		release = region_flt[r][AMPEG_RELEASE] * 1000;

/* ramp from 0 to <volume> in <attack> msecs */
	sp->envelope_offset[ATTACK] = to_offset (volume);
	sp->envelope_rate[ATTACK] = calc_rate (volume, attack);

/* ramp down HOLD_EXCURSION in <hold> msecs */
	sp->envelope_offset[HOLD] = to_offset (volume - HOLD_EXCURSION);
	sp->envelope_rate[HOLD] = calc_rate (HOLD_EXCURSION, hold);

/* ramp down by <sustain> in <decay> msecs */
	if (sustain <= ENV_BOTTOM) sustain = ENV_BOTTOM;
	if (sustain > volume - HOLD_EXCURSION) sustain = volume - HOLD_EXCURSION;

	sp->envelope_offset[DECAY] = to_offset (sustain);
	sp->envelope_rate[DECAY] = calc_rate (volume - HOLD_EXCURSION - sustain, decay);
	if (fast_decay) sp->envelope_rate[DECAY] *= 2;

/* ramp to ENV_BOTTOM in ?? msec */
	sp->envelope_offset[RELEASE] = to_offset (ENV_BOTTOM);
	sp->envelope_rate[RELEASE] = calc_rate (255, release);

	if (fast_decay) sp->envelope_rate[RELEASE] *= 2;

	sp->envelope_offset[RELEASEB] = to_offset (ENV_BOTTOM);
	sp->envelope_rate[RELEASEB] = to_offset (200);
	sp->envelope_offset[RELEASEC] = to_offset (ENV_BOTTOM);
	sp->envelope_rate[RELEASEC] = to_offset (200);

	sp->envelope_rate[DELAY] = (int32) ((delay * play_mode->rate) / 1000);

	sp->modes |= MODES_ENVELOPE;

	if (region[r][LOOP_MODE] == VAL_LOOP_SUSTAIN) sp->modes |= (MODES_LOOPING|MODES_SUSTAIN);

	nullify_extras(sp);

	if (region[r][GROUP] == region[r][OFF_BY])
		sp->exclusiveClass = region[r][OFF_BY];
	else sp->exclusiveClass = 0;

	if (region[r][TRIGGER] == VAL_TRIGGER_LEGATO) sp->trigger = TRIGGER_LEGATO;
	else sp->trigger = TRIGGER_NONE;


	if (b->tone[tn].cutoff != -1) sp->cutoff_freq = b->tone[tn].cutoff;
	else sp->cutoff_freq = 0;

	if (note_to_use != -1)
	    sp->note_to_use = (uint8) (note_to_use);
	else if (percussion) sp->note_to_use = region[r][PITCH_KEYCENTER];
	else sp->note_to_use = 0;

	if (b->tone[tn].sustain != -1 && sp->modes & MODES_LOOPING) {
	    if (b->tone[tn].sustain == 1) sp->modes |= MODES_SUSTAIN;
	    else sp->modes &= ~MODES_SUSTAIN;
	}

	/* Strip any loops and envelopes we're permitted to */
	if ((strip_loop == 1) &&
	    (sp->modes & (MODES_SUSTAIN | MODES_LOOPING |
			  MODES_PINGPONG | MODES_REVERSE))) {
	    ctl->cmsg (CMSG_INFO, VERB_DEBUG,
		       " - Removing loop and/or sustain");
	    sp->modes &=
		~(MODES_SUSTAIN | MODES_LOOPING | MODES_PINGPONG |
		  MODES_REVERSE);
	}

	if (strip_envelope == 1) {
	    if (sp->modes & MODES_ENVELOPE)
		ctl->cmsg (CMSG_INFO, VERB_DEBUG,
			   " - Removing envelope");
	    sp->modes &= ~MODES_ENVELOPE;
	}

	if (amp != -1)
	    sp->volume = (double) (amp) / 100.0;
	else if (sfz_volume > 0.1 || sfz_volume < -0.1)
		sp->volume = TO_VOLUME(sfz_volume);
	else sp->volume = 1.0;

	sp->amp_random = region_flt[r][AMP_RANDOM];
	sp->hirand = region_flt[r][HIRAND];
	sp->lorand = region_flt[r][LORAND];

	sp->data_length /= 2;	/* These are in bytes. Convert into samples. */

	if (sp->samplesize > 16) sp->data_length /= 2;

	/* The sample must be padded out by 1 extra sample, so that
	   round off errors in the offsets used in interpolation will not
	   cause a "pop" by reading random data beyond data_length */
	//sp->data[sp->data_length] = sp->data[sp->data_length - 1];

	/* Then fractional samples */
	sp->data_length <<= FRACTION_BITS;
	sp->loop_start <<= FRACTION_BITS;
	sp->loop_end <<= FRACTION_BITS;

	if (strip_tail == 1) {
	   ctl->cmsg (CMSG_INFO, VERB_DEBUG, " - Stripping tail");
	   sp->data_length = sp->loop_end;
	}

}

#endif

int read_sfz_file(const char *name)
{
	int retvalue = 0;
	include_stack_ptr = 0;
	rcf_count = 1;

#ifdef LOADER
	yyin = open_file (name, 1, OF_NORMAL, 0);
#else
	yyin = fopen(name, "r");
#endif
	if (!yyin) return -1;

	if (this_fname[include_stack_ptr]) free(this_fname[include_stack_ptr]);
	this_fname[include_stack_ptr] = strdup(name);

	BEGIN(K);
	retvalue = yylex();
	fclose(yyin);
	if (!retvalue) leave_region();
	return retvalue;
}

#ifndef LOADER
static char outfile[80];

int main(int argc, char **argv)
{
	int32 c, i;

	byteorder();

	for (i = FIRST_SFZ_PARM; i < MAX_SFZ_PARM; i++) group_parm[i] = default_parm[i];
	for (i = 0; i < MAX_SFZ_PARM; i++) region_parm[i] = group_parm[i];

	while ((c=getopt(argc, argv, "v"))>0)
	    switch(c) {
		case 'v': verbosity++; break;
		default: return 1;
	    }

	if (optind==argc-1) {

		strcpy(outfile, argv[optind]);
		if (!strcmp(outfile + strlen(outfile) - 4, ".sfz"))
			outfile[ strlen(outfile) - 4 ] = '\0';
		strcat(outfile, ".pat");
		initialize_sfz();
		if (read_sfz_file(argv[optind])) {
			perror("sfz2pat: I can't open your SFZ");
			return 3;
		}
		make_pat();
	}
	else if (optind!=argc) {
      		fprintf(stderr, 
	      		"Usage: sfz2pat [-r RootFreq | -n Note] [-u Note] [-v] [filename]\n");
      		return 1;
	}

	return 0;
}
#else

void
free_sfz_data(InstrumentLayer *lp)
{
	int g = lp->sfz_group, ng, i;

SFZDBG
"freeing sfz");
	while (g >= 0) {
	    if (sample_left_buf[g]) free(sample_left_buf[g]);
	    if (sample_right_buf[g]) free(sample_right_buf[g]);
	    sample_left_buf[g] = NULL;
	    sample_right_buf[g] = NULL;
	    for (i = 0; i < MAX_SFZ_REGION; i++) if (region[i][REGION_IN_GROUP] == g) {
		if (region_left_sample[i]) free(region_left_sample[i]);
		if (region_right_sample[i]) free(region_right_sample[i]);
		region_left_sample[i] = NULL;
		region_right_sample[i] = NULL;
		region[i][REGION_IS_BUSY] = FALSE;
		region[i][REGION_IN_GROUP] = -1;
	    }
	    ng = group_link[g];
	    group_link[g] = GROUP_IS_FREE;
	    g = ng;
	}
}

#define MAX_VLAYER 128

InstrumentLayer *
load_sfz_instrument (ToneBank *b, int bank, int tn, int percussion)
{
	int32 i, r, l_ix, r_ix, g;
        InstrumentLayer *lp = NULL, *lastlp, *headlp = NULL;
	Instrument *ip;
	Sample *sp = NULL;
	const char *name = b->tone[tn].name;
    	int note_to_use = b->tone[tn].note;
	int vlayer_count, hivel, lovel;
	int vlayer, vlayer_list[MAX_VLAYER][4];
	int vlayer_region_left[MAX_VLAYER][MAX_SFZ_REGION];
	int stereo_layer, stereo_channels = 1, right_samples;

SFZDBG
"load %s", name);
	initialize_sfz();
	if (read_sfz_file(name)) {
		SFZERR
		"Couldn't read %s SFZ file", name);
		return NULL;
	}
SFZDBG
"sfz read ok");

	if (note_to_use == -1 && percussion) note_to_use = tn;


	point_regions_to_groups();

SFZDBG
"pointed ok");
	vlayer_count = 0;
	for (vlayer = 0; vlayer < MAX_VLAYER; vlayer++)
		 vlayer_list[vlayer][0] =
		 vlayer_list[vlayer][1] =
		 vlayer_list[vlayer][2] =
		 vlayer_list[vlayer][3] = 0;

	g = first_group;

	while (g >= 0) {
	    for (i = 0; i < MAX_SFZ_REGION; i++) if (region[i][REGION_IN_GROUP] == g) {
		hivel = region[i][HIVEL];
		lovel = region[i][LOVEL];
		for (vlayer = 0; vlayer < vlayer_count; vlayer++)
			if (vlayer_list[vlayer][0] == lovel && vlayer_list[vlayer][1] == hivel) break;
		if (vlayer == vlayer_count) {
			vlayer_list[vlayer][0] = lovel;
			vlayer_list[vlayer][1] = hivel;
			if (vlayer_count < MAX_VLAYER - 1) vlayer_count++;
		}
SFZDBG
"counting layer %d", vlayer_count);
		vlayer_region_left[vlayer][vlayer_list[vlayer][2] ] = i;
		if (region_left_sample[i]) vlayer_list[vlayer][2]++;
		if (region_right_sample[i]) vlayer_list[vlayer][3]++;
	    }
SFZDBG
"link from %d to %d", g, group_link[g]);

	    g = group_link[g];
	}

SFZDBG
"counted %d layers", vlayer_count);

	lastlp = NULL;

  for (vlayer = 0; vlayer < vlayer_count; vlayer++) {

	if (fast_load && vlayer > 0) break;

	lp = (InstrumentLayer *) safe_malloc (sizeof (InstrumentLayer));
	lp->size = 0;
	lp->map_size = 0;
	lp->all_layers = NULL;
	lp->lo = vlayer_list[vlayer][0];
	lp->hi = vlayer_list[vlayer][1];
	ip = (Instrument *) safe_malloc (sizeof (Instrument));
	lp->instrument = ip;
	lp->purgelist = NULL;
	lp->next = NULL;
	lp->font_type = FONT_SFZ;
	lp->sfz_group = first_group;

	if (lastlp) lastlp->next = lp;
	else {
		headlp = lp;
	}

	lastlp = lp;

	ip->type = FONT_SFZ;
	ip->samples = vlayer_list[vlayer][2];
	ip->sample = (Sample *) safe_malloc (sizeof (Sample) * ip->samples);
	ip->left_samples = ip->samples;
	ip->left_sample = ip->sample;
	right_samples = vlayer_list[vlayer][3];
	ip->right_samples = right_samples;
	if (right_samples) {
	    ip->right_sample =
		(Sample *) safe_malloc (sizeof (Sample) * right_samples);
	    stereo_channels = 2;
	}
	else
	    ip->right_sample = 0;
	ip->contents = NULL;

	l_ix = r_ix = 0;

	if (!vlayer)
	ctl->cmsg (CMSG_LOAD, VERB_NOISY,
		   "%s%s[%d,%d] %s(%d layer%s)",
		   (percussion) ? "   " : "", name,
		   (percussion) ? note_to_use : tn, bank,
		   (right_samples) ? "(2) " : "", vlayer_count, (vlayer_count>1)? "s":"");

   for (stereo_layer = 0; stereo_layer < stereo_channels; stereo_layer++) {
    int     sample_count;
    sample_count = ip->left_samples;

    for (i = 0; i < sample_count; i++) {
	int32 region_start, region_end, region_bytes;
	int32 datasize, data_width, loop_start, loop_end;
	unsigned char *left_buf, *right_buf;

	r = vlayer_region_left[vlayer][i];
	datasize = region_datasize[r];
	left_buf = region_left_sample[r];
	right_buf = region_right_sample[r];
	data_width = region_samplesize[r]/8;
	if (data_width == 3) data_width = 4;
	if (stereo_layer && !right_buf) continue;

	region_start = region[r][OFFSET];
	region_end = region[r][END];
	if (region_end <= 0) region_end = datasize/data_width;

	if (!region[r][LOOP_START]) loop_start = 0;
	else loop_start = region[r][LOOP_START] - region_start;
	if (!region[r][LOOP_END]) loop_end = region_end - region_start;
	else loop_end = region[r][LOOP_END] - region_start;

	region_bytes = (region_end - region_start) * data_width;

	if (region_bytes / data_width > MAX_SAMPLE_SIZE) {
	    ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
		       "Sample length of %d is too big for me to handle (max is %d).",
		       region_bytes/data_width, MAX_SAMPLE_SIZE);
	    region_bytes = data_width * MAX_SAMPLE_SIZE;
	    if (loop_end > MAX_SAMPLE_SIZE) loop_end = MAX_SAMPLE_SIZE;
	    if (loop_start > loop_end) loop_start = 0;
	}
//printf("region %d has %d bytes of %d total (%d samples of %d)\n", r, region_bytes, datasize, region_bytes/2, datasize/2);
//printf("\tregion_start %d, region_end %d\n", region_start, region_end);
//printf("\tloop_start %d, loop_end %d\n", loop_start, loop_end);
//printf("\tvolume %f -> %f, ampeg_release %f, loop_mode %d\n",
//	region_flt[r][VOLUME],
//	TO_VOLUME(region_flt[r][VOLUME]),
//	region_flt[r][AMPEG_RELEASE], region[r][LOOP_MODE]);


	if (!stereo_layer) {
		sp = &(ip->left_sample[l_ix++]);
		if (right_buf) sp->stereo_mode = LEFT_SAMPLE;
		else sp->stereo_mode = MONO_SAMPLE;
		if (data_width == 4)
		    sp->ldata = (samplel_t *)(left_buf + region_start * data_width);
		else sp->data = (sample_t *)(left_buf + region_start * data_width);
	}
	else {
		sp = &(ip->right_sample[r_ix++]);
		sp->stereo_mode = RIGHT_SAMPLE;
		if (data_width == 4)
		    sp->ldata = (samplel_t *)(right_buf + region_start * data_width);
		else sp->data = (sample_t *)(right_buf + region_start * data_width);
	}
	sp->data_length = region_bytes;
	headlp->size += sp->data_length;
	sp->loop_start = loop_start;
	sp->loop_end = loop_end;
	sp->samplesize = region_samplesize[r];
	make_sample(sp, b, tn, percussion, r);

    }		/* end of sample loop */

   }		/* end of stereo layer loop */
  }		/* end of vlayer loop */

    return headlp;
}

#endif

static
int read_sample(char *name)
{
	int32 samplerate=-1, datasize=-1, all_length, chunk_length, c, i;
      	int32 aiff_offset=-1, aiff_blocksize=-1, aiff_numsamples=-1, samplesize = 16;
	int32 left_datasize, right_datasize, data_width=2;
	int infd=STDIN_FILENO;
	unsigned char thing[4096], modes=0;
	unsigned char	*sample_buf = NULL, *left_buf, *right_buf;
	int stereo_channels = 1;

#ifdef LOADER
	if ((infd=open_file_raw (name, OF_NORMAL, 0))<0) {
#else
	if ((infd=open(name, O_RDONLY))<0) {
#endif
		SFZERR
      		"sfz2pat: I can't open your sample file %s", name);
      		return 3;
	}
	if (read(infd, thing, 12)<=0) {
		SFZERR
      		"sfz2pat: I can't read your WAVE");
      		return 3;
	}

	if (!memcmp(thing+4, "WAVE", 4)) {
		/* wave */
		all_length=LE_LONG(*((int32 *)(thing)));
		for (i = 0; i < 4; i++) thing[i] = thing[i+8];
		if (read(infd, thing+4, 4) != 4) {
			SFZERR
			"sfz2pat: I can't read your WAVE");
			return 3;
		}

	}
	else if (!memcmp(thing, "RIFF", 4)) {
		/* wave */
		all_length=LE_LONG(*((int32 *)(thing+4)));
		if (memcmp(thing+8, "WAVE", 4)) {
			SFZERR
			"File format not recognized");
			return 1;
		}
		if (read(infd, thing, 8) != 8) {
			SFZERR
			"sfz2pat: I can't read your WAVE");
			return 3;
		}
	}
	else if (!memcmp(thing, "FORM", 4)) {
	    /* aiff */
	    all_length=LE_LONG(*((int32 *)(thing+4)));
	    if (memcmp(thing+8, "AIFF", 4)) {
		SFZERR
		"File format not recognized");
		return 1;
	    }
		/* now look for SSND and COMM chunks */
	    while (datasize == -1 || aiff_offset == -1) {
		if (read(infd, thing, 8) != 8) {
			SFZERR
			"sfz2pat: I can't read your AIFF");
			return 3;
		}
      		chunk_length=BE_LONG(*((int32 *)(thing+4)));
		if (!chunk_length) break;
		SFZDBG
		"Chunk type %c%c%c%c", thing[0],thing[1],thing[2],thing[3]);
		SFZNL
		SFZDBG
		"Chunk length %d", chunk_length);
		SFZNL
		if (!memcmp(thing, "SSND", 4)) {
		    if (chunk_length < 8 || read(infd, thing, 8) != 8) {
			SFZERR
			"sfz2pat: I can't read your AIFF");
			return 3;
		    }
		    chunk_length -= 8;
      		    aiff_offset = BE_LONG(*((int32 *)thing));
      		    aiff_blocksize = BE_LONG(*((int32 *)(thing+4)));
		}
		else if (!memcmp(thing, "COMM", 4)) {
		    if (chunk_length < 18 || read(infd, thing, 18) != 18) {
			SFZERR
			"sfz2pat: I can't read your AIFF");
			return 3;
		    }
		    chunk_length -= 18;
	  	    stereo_channels = BE_SHORT(*((int16 *)thing));
      		    aiff_numsamples = BE_LONG(*((int32 *)(thing+2)));
	  	    samplesize = BE_SHORT(*((int16 *)(thing+6)));
		    if (samplesize == 8) data_width = 1;
		    else if (samplesize != 16) {
			SFZERR
			"Can't handle sample size %d in AIFF file", samplesize);
			return 1;
		    }
	  	    switch(samplesize) {
	    	    	case 8: data_width = 1; break;
	    	    	case 16: modes |= MODES_16BIT; break;
	  	    }
		    datasize = aiff_numsamples * data_width * stereo_channels;

		/* Is the frequency outside of what we can represent with Uint32? */
		    if ( (thing[8+0] & 0x80) || (thing[8+0] <= 0x3F) || (thing[8+0] > 0x40)
			|| (thing[8+0] == 0x40 && thing[8+1] > 0x1C) )
				samplerate = 0;
		    else samplerate = ((thing[8+2] << 23) | (thing[8+3] << 15) | (thing[8+4] << 7)
			| (thing[8+5] >> 1)) >> (29 - thing[8+1]);

		}
		else {
			SFZERR
		"Chunk type %c%c%c%c", thing[0],thing[1],thing[2],thing[3]);
			SFZERR
		"Unknown AIFF chunk");
	  	    if (chunk_length & 1) chunk_length++;

	  	    while (chunk_length>0) {
	      	        if ((c=read(infd, thing, (chunk_length>4096) ? 4096 : chunk_length)) <= 0) {
				SFZERR
		  	    "sfz2pat: Now your AIFF has run out of data");
		  	    return 3;
	      	        }
	      	        chunk_length -= c;
	  	    }
		}
	    }
	    SFZDBG
	    "AIFF: offset %d, blocksize %d, channels %d, samples %d",
		aiff_offset, aiff_blocksize, stereo_channels, aiff_numsamples);
	    SFZNL
	    SFZDBG
	    "AIFF: samplesize %d, samplerate %d, chunk left %d, datasize %d",
		samplesize, samplerate, chunk_length, datasize);
	    SFZNL
	  	    while (aiff_offset>0 && aiff_offset < chunk_length) {
	      	        if ((c=read(infd, thing, (aiff_offset>4096) ? 4096 : aiff_offset)) <= 0) {
				SFZERR
		  	    "sfz2pat: Now your AIFF has run out of data");
		  	    return 3;
	      	        }
	      	        aiff_offset -= c;
			chunk_length -= c;
	  	    }
	    if (datasize > chunk_length) {
		SFZERR
		"AIFF file is too short\n");
		return 1;
	    }
	}
	else if (!memcmp(thing, "OggS", 4)) {
		/* ogg */
#ifndef HAVE_OGG
		SFZERR
		"OGG format not implemented");
		return 1;
#else
	OggVorbis_File vf;
	int eof=0;
	int current_section, sample_point = 0;
	FILE *f;

	close (infd);
#ifdef LOADER
	f = fopen(current_filename, "r");
#else
	f = fopen(name, "r");
#endif
	if (ov_open(f, &vf, NULL, 0) < 0) {
		SFZERR
			"%s does not appear to be an Ogg bitstream.", name);
		return 1;;
	}
      {
	//char **ptr=ov_comment(&vf,-1)->user_comments;
	vorbis_info *vi=ov_info(&vf,-1);
	//while(*ptr){
	//  fprintf(stderr,"%s\n",*ptr);
	//  ++ptr;
	//}
	stereo_channels = vi->channels;
	samplerate = vi->rate;
	SFZDBG
    		"Bitstream is %d channel, %ldHz",vi->channels,vi->rate);
	SFZNL
	datasize = 2 * ov_pcm_total(&vf,-1);
	SFZDBG
    		"Decoded length: %d samples", datasize/2);
	SFZNL
	//fprintf(stderr,"Encoded by: %s\n\n",ov_comment(&vf,-1)->vendor);
      }

	sample_buf = (unsigned char *)malloc(datasize);
	samplesize = 16;
	modes |= MODES_16BIT;

  while(!eof){
	long ret = ov_read(&vf, sample_buf, datasize, 0, 2, 1, &current_section);
    if (ret == 0) {
      /* EOF */
      eof=1;
    } else if (ret < 0) {
      /* error in the stream.  Not a problem, just reporting it in
	 case we (the app) cares.  In this case, we don't. */
    } else {
      /* we don't bother dealing with sample rate changes, etc, but
	 you'll have to*/
      //fwrite(pcmout,1,ret,stdout);
	sample_point += ret;
	//SFZDBG
    	//	"read %d bytes of %d", sample_point, datasize);
	//SFZNL
    }
  }

  ov_clear(&vf);
    
  //fprintf(stderr,"Done.\n");

#endif
	}
	else if (!memcmp(thing, "CREA", 4)) {
		/* voc */
		SFZERR
		"VOC format not implemented");
		return 1;
	}

  if (datasize == -1) chunk_length=LE_LONG(*((int32 *)(thing+4)));

  while (datasize==-1) {
      /* This Microsoft file format is designed to be impossible to
	 parse correctly if one doesn't have the full specification.
	 If you have a wave with an INFO "chunk", you lose. Thank you
	 for playing. */

      if (!memcmp(thing, "fmt ", 4)) {
	  if (chunk_length > 4096) {
		SFZERR
		      "WAVEs with %d-byte format blocks make me throw up!\n",
		      chunk_length);
	      return 2;
	  }
	  if (read(infd, thing, chunk_length) != chunk_length) {
		SFZERR
	      "sfz2pat: Your WAVE is mangled");
	      return 3;
	  }
	  if (LE_SHORT(*((int16 *)(thing))) != 1) {
		SFZERR
	      "sfz2pat: I don't understand your WAVE. "
		      "It has a type %d format chunk!",
		      LE_SHORT(*((int16 *)(thing))));
	      return 2;
	  }
	  stereo_channels = LE_SHORT(*((int16 *)(thing + 2)));
	  if (stereo_channels < 1 || stereo_channels > 2) {
		SFZERR
	      "sfz2pat: This WAVE has %d channels! " 
		      "There can be at most two.", stereo_channels);
	      return 2;
	  }
	  samplerate = LE_LONG(*((int32 *)(thing + 4)));
	  samplesize = LE_SHORT(*((int16 *)(thing + 14)));
	  switch(samplesize) {
	    case 8: modes |= MODES_UNSIGNED; data_width = 1; break;
	    case 16: modes |= MODES_16BIT; break;
	    case 24: modes |= MODES_16BIT; data_width = 3; break;
	    default:
		SFZERR
	      "sfz2pat: Ack! Ppthbth! %d-bit samples!", samplesize);
	      return 2;
	  }
	    SFZNOTE
	    "%s is a %d-bit, %d channel, %d Hz WAVE", name,
		    (LE_SHORT(*((int16 *)(thing + 14)))),
		    stereo_channels,
		    samplerate);
	    SFZNL
      }
      else if (!memcmp(thing, "data", 4)) {
	  if (samplerate==-1) {
		SFZERR
	      "sfz2pat: Your WAVE has no format information before data!");
	      return 2;
	  }
	  SFZNOTE
	    "It has %d bytes of data and sample length %d", chunk_length, chunk_length/stereo_channels/data_width);
	  datasize=chunk_length;
	  SFZNL
      }
      else {
	  SFZNOTE
		    "Your WAVE has a %d-byte chunk called `%4.4s'\n",
		    chunk_length, thing);
	  SFZNL

	  /* It's cool to pad chunks with NULs to align them on
             half-word boundaries. */
	  if (chunk_length & 1) chunk_length++;

	  while (chunk_length>0) {
	      if ((c=read(infd, thing, (chunk_length>4096) ? 4096 : chunk_length)) <= 0) {
		SFZERR
		  "sfz2pat: Now your WAVE has run out of data");
		  return 3;
	      }
	      chunk_length -= c;
	  }
      }
      if (datasize != -1) break;
      if (read(infd, thing, 8)!=8) {
		SFZERR
		 "Your WAVE ran out before I got to the interesting bits");
	  return 3;
      }
      chunk_length=LE_LONG(*((int32 *)(thing+4)));
    }

	/* if it was an ogg, sample_buf has been filled */
    if (!sample_buf) {
	int offset_read = 0;
	if (data_width == 3) offset_read = 1;
	/* malloc 1 extra so following conversion from 24 to 32 bits doesn't go past end */
	sample_buf = (unsigned char *)malloc(datasize + offset_read);
	if ((c=read(infd, sample_buf + offset_read, datasize)) != datasize) {
		SFZERR
		"sfz2pat: I can't read the data");
		close(infd);
		return 3;
	}
	close(infd);
    }

#ifdef LOADER
	if (data_width == 3) {
		int32   data_len = datasize / 3, t = 0;
		unsigned char  *cp = sample_buf;
		int32 *tmpdta, *newdta;

		datasize = data_len * 4;
		tmpdta = newdta = malloc (datasize);
		while (data_len--) {
      			*tmpdta = LE_LONG(*((int32 *)(cp+t)));
			*tmpdta >>= 8;
			tmpdta++;
			t += 3;
		}
		cp = (unsigned char *) (sample_buf);
		sample_buf = (unsigned char *) newdta;
		free (cp);
		samplesize = 24;
		data_width = 4;
	}
#else
	if (data_width == 3) {
		int32   data_len = datasize / 3, t = 2;
		unsigned char  *cp = sample_buf;
		int16 *tmpdta, *newdta;
		datasize = data_len * 2;
		tmpdta = newdta = malloc (datasize);
		while (data_len--) {
      			*tmpdta++ = LE_SHORT(*((int16 *)(cp+t)));
			t += 3;
		}
		cp = (unsigned char *) (sample_buf);
		sample_buf = (unsigned char *) newdta;
		free (cp);
		samplesize = 16;
		data_width = 2;
	}
#endif

	if (stereo_channels == 2) {
		left_datasize = right_datasize = datasize/2;
	}
	else {
		left_datasize = datasize;
		right_datasize = 0;
	}

	if (data_width == 2) {
#ifdef LOADER
#ifdef LITTLE_ENDIAN
	if (aiff_numsamples > 0) {
		unsigned char onebyte;
		for (i = 0; i < datasize; i+= 2) {
			onebyte = sample_buf[i];
			sample_buf[i] = sample_buf[i+1];
			sample_buf[i+1] = onebyte;
		}
	}
#else
	    /* convert to machine byte order */
	{
	    int32   data_len = datasize / 2;
	    int16  *tmpdta = (int16 *) sample_buf, s;
	    while (data_len--) {
		s = LE_SHORT (*tmpdta);
		*tmpdta++ = s;
	    }
	}
#endif
#else
	if (big_endian || (!big_endian && aiff_numsamples > 0)) {
		unsigned char onebyte;
		for (i = 0; i < datasize; i+= 2) {
			onebyte = sample_buf[i];
			sample_buf[i] = sample_buf[i+1];
			sample_buf[i+1] = onebyte;
		}
	}
#endif
	}

	if (samplesize == 8) {	/* convert to 16-bit data */
		int32   data_len = datasize;
		unsigned char  *cp = sample_buf;
		uint16 *tmpdta, *newdta;
		tmpdta = newdta = malloc (datasize * 2);
		while (data_len--)
			*tmpdta++ = (uint16) (*cp++) << 8;
		cp = (unsigned char *) (sample_buf);
		sample_buf = (unsigned char *) newdta;
		free (cp);
		datasize *= 2;
		left_datasize *= 2;
		right_datasize *= 2;
		samplesize = 16;
		data_width = 2;
		modes |= MODES_16BIT;
	}

	if (modes & MODES_UNSIGNED) {	/* convert to signed data */
	    int32   data_len = datasize / 2;
	    int16  *tmpdta = (int16 *) sample_buf;
	    while (data_len--)
		*tmpdta++ ^= 0x8000;
	    modes &= ~MODES_UNSIGNED;
	}

	if (am_in_region) {
	    region_datasize[current_region] = left_datasize;
	    region_channels[current_region] = stereo_channels;
	    region_modes[current_region] = modes;
	    region_samplerate[current_region] = samplerate;
	    region_samplesize[current_region] = samplesize;
	}
	else {
	    sample_left_datasize[current_group] = left_datasize;
	    sample_right_datasize[current_group] = right_datasize;
	    sample_channels[current_group] = stereo_channels;
	    sample_modes[current_group] = modes;
	    sample_samplerate[current_group] = samplerate;
	    sample_samplesize[current_group] = samplesize;
	}

	if (stereo_channels == 1) {
		if (am_in_region) {
		    region_left_sample[current_region] = sample_buf;
		    region_right_sample[current_region] = NULL;
		}
		else {
		    sample_left_buf[current_group] = sample_buf;
		    sample_right_buf[current_group] = NULL;
		}
		return 0;
	}

	left_buf = (unsigned char *)malloc(datasize/2);
	right_buf = (unsigned char *)malloc(datasize/2);

	if (data_width == 2) {
		int32   data_len = datasize/4;
		int16  *tmpdta = (int16 *) sample_buf;
		int16  *ldta = (int16 *) left_buf;
		int16  *rdta = (int16 *) right_buf;

	    	while (data_len--) {
			*ldta++ = *tmpdta++;
			*rdta++ = *tmpdta++;
		}
	}
	else if (data_width == 4) {
		int32   data_len = datasize/8;
		int32  *tmpdta = (int32 *) sample_buf;
		int32  *ldta = (int32 *) left_buf;
		int32  *rdta = (int32 *) right_buf;

	    	while (data_len--) {
			*ldta++ = *tmpdta++;
			*rdta++ = *tmpdta++;
		}
	}

	if (am_in_region) {
	    region_left_sample[current_region] = left_buf;
	    region_right_sample[current_region] = right_buf;
	}
	else {
	    sample_left_buf[current_group] = left_buf;
	    sample_right_buf[current_group] = right_buf;
	}

	free(sample_buf);

	return 0;
}

static void
leave_region(void)
{
	int i;

	if (!am_in_region) return;
	for (i = 0; i < MAX_SFZ_PARM; i++)
		region[current_region][i] = region_parm[i];
	for (i = 0; i < MAX_FLOAT_PARM; i++)
		region_flt[current_region][i] = region_flt_parm[i];
	region[current_region][REGION_IS_BUSY] = TRUE;
	current_region = -1;
	am_in_region = FALSE;
}

static int
enter_region(void)
{
	int i;
	if (am_in_region) return FALSE;
	for (i = 0; i < MAX_SFZ_REGION; i++) if (!region[i][REGION_IS_BUSY]) break;
	if (i < MAX_SFZ_REGION) {
		current_region = i;
		am_in_region = TRUE;
		return TRUE;
	}
	return FALSE;
}

static void
leave_group(void)
{
	if (!am_in_group) return;
	previous_group = current_group;
	current_group = -1;
	am_in_group = FALSE;
}

static int
enter_group(void)
{
	int i;
	if (am_in_group) return TRUE;
	for (i = 0; i < MAX_SFZ_GROUP; i++) if (group_link[i] == GROUP_IS_FREE) break;
	if (i < MAX_SFZ_GROUP) {
		current_group = i;
		if (first_group == -1) {
			first_group = current_group;
		}
		else if (previous_group != -1) group_link[previous_group] = current_group;
		/* else error ? */
		group_link[current_group] = -2;
		am_in_group = TRUE;
		return TRUE;
	}
	return FALSE;
}


static void
point_regions_to_groups(void)
{	int i, g;

	g = first_group;

	while (g >= 0) {
	    for (i = 0; i < MAX_SFZ_REGION; i++) if (region[i][REGION_IN_GROUP] == g) {
		if (region_left_sample[i]) continue;
		//g = region[i][REGION_IN_GROUP];
		//while (!sample_left_buf[g] && g > 0) g--;
		region_left_sample[i] = sample_left_buf[g];
		region_right_sample[i] = sample_right_buf[g];
		region_samplerate[i] = sample_samplerate[g];
		region_samplesize[i] = sample_samplesize[g];
		region_datasize[i] = sample_left_datasize[g];
		region_modes[i] = sample_modes[g];
	    }
SFZDBG
"point: link %d to %d", g, group_link[g]);
	    g = group_link[g];
	}
}

#ifndef LOADER

#define MAX_VLAYER 19

static void
make_pat(void)
{
	int32 i, r, g;
	int stereofd;
	struct pat_header header;
	struct sample_header sample;
	unsigned char buf[1024];
	int vlayer_count, hivel, lovel;
	int     vlayer, vlayer_list[MAX_VLAYER][4];
	int vlayer_region_left[MAX_VLAYER][MAX_SFZ_REGION];
	int stereo_layer, stereo_channels = 0, left_sample_count = 0, right_sample_count = 0;
	int32 total_region_bytes = 0;

	point_regions_to_groups();

	vlayer_count = 0;
	for (vlayer = 0; vlayer < MAX_VLAYER; vlayer++)
		 vlayer_list[vlayer][0] =
		 vlayer_list[vlayer][1] =
		 vlayer_list[vlayer][2] =
		 vlayer_list[vlayer][3] = 0;

	g = first_group;

	while (g >= 0) {
	    for (i = 0; i < MAX_SFZ_REGION; i++) if (region[i][REGION_IN_GROUP] == g) {
		if (region_left_sample[i]) left_sample_count++;
		if (region_right_sample[i]) right_sample_count++;
		hivel = region[i][HIVEL];
		lovel = region[i][LOVEL];
		for (vlayer = 0; vlayer < vlayer_count; vlayer++)
			if (vlayer_list[vlayer][0] == lovel && vlayer_list[vlayer][1] == hivel) break;
		if (vlayer == vlayer_count) {
			vlayer_list[vlayer][0] = lovel;
			vlayer_list[vlayer][1] = hivel;
			if (vlayer_count < MAX_VLAYER - 1) vlayer_count++;
		}
		vlayer_region_left[vlayer][vlayer_list[vlayer][2] ] = i;
		if (region_left_sample[i]) vlayer_list[vlayer][2]++;
		if (region_right_sample[i]) vlayer_list[vlayer][3]++;
	    }

	    g = group_link[g];
	}
	if (left_sample_count) stereo_channels = 1;
	if (right_sample_count) stereo_channels = 2;

	memset((char *)&header, 0, sizeof(header));  /* patch header is 239, sample header is 96. sum = 335 */
	memcpy(header.magic, "GF1PATCH110", 12);
	memcpy(header.version, "ID#000002", 10);
	strcpy(header.description, "Copyleft 1995 EWE&U Conductions and one Retreated Gravi\032");
	header.instruments = 1;
	header.pat_voices = 14;
	header.pat_channels = 0;
	header.nr_waveforms = vlayer_list[0][2];
	header.master_volume = 127;
	header.data_size = 0; /* ?? */
	memcpy(header.sf2magic, "SF2EXT\0", 7);
	header.instrument_number = 1;
	strcpy(header.instrument_name, "Bleahnoise");
	header.instrument_size = 0; /* ?? sample_left_datasize + sample_right_datasize; */
	header.layer_count = 1;
/* sf2layer[9] */
	header.layer_duplicate = 0;
	header.layer_number = 0;
	header.layer_size = 0; /* ?? */
	header.num_samples = vlayer_list[0][2];
/* sf2layer2[10] */

	header.velocity_count = vlayer_count;
	for (i = 0; i < 9; i++) {
		header.sf2layer[i].velmin = vlayer_list[i][0];
		header.sf2layer[i].velmax = vlayer_list[i][1];
		header.sf2layer[i].left_samples = vlayer_list[i][2];
		header.sf2layer[i].right_samples = vlayer_list[i][3];
	}
	for (i = 0; i < 10; i++) {
		header.sf2layer2[i].velmin = vlayer_list[i+9][0];
		header.sf2layer2[i].velmax = vlayer_list[i+9][1];
		header.sf2layer2[i].left_samples = vlayer_list[i+9][2];
		header.sf2layer2[i].right_samples = vlayer_list[i+9][3];
	}
	//vlayer_list[0][0] = header.sf2layer[0].velmin = 0;
	//vlayer_list[0][1] = header.sf2layer[0].velmax = 127;
	//vlayer_list[0][2] = header.sf2layer[0].left_samples = left_sample_count;
	//vlayer_list[0][3] = header.sf2layer[0].right_samples = right_sample_count;

	memcpy (buf, (char *) &header, sizeof (header));
	fix_header_write(buf, &header);


	if ((stereofd = open(outfile, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) {
		fprintf(stderr, "Can't open output file %s\n", outfile);
		return;
	}

	if ( write(stereofd, buf, sizeof(header)) != sizeof(header) ) {
		fprintf(stderr, "Write error\n");
		return;
	}


  for (vlayer = 0; vlayer < vlayer_count; vlayer++) {

   for (stereo_layer = 0; stereo_layer < stereo_channels; stereo_layer++) {

    for (i = 0; i < vlayer_list[vlayer][2]; i++) {
	int32 region_start, region_end, region_bytes;
	int32 datasize, data_width, loop_start, loop_end;
	unsigned char *left_buf, *right_buf;

	r = vlayer_region_left[vlayer][i];
	datasize = region_datasize[r];
	left_buf = region_left_sample[r];
	right_buf = region_right_sample[r];
	data_width = region_samplesize[r]/8;
	if (stereo_layer && !right_buf) continue;

/* sample header */  
	memset((char *)&sample, 0, sizeof(sample));  /* patch header is 239, sample header is 96. sum = 335 */

	region_start = region[r][OFFSET];
	region_end = region[r][END];
	if (region_end <= 0) region_end = datasize/data_width;
	region_bytes = (region_end - region_start) * data_width;
	total_region_bytes += region_bytes;

	if (!region[r][LOOP_START]) loop_start = 0;
	else loop_start = region[r][LOOP_START] - region_start;
	if (!region[r][LOOP_END]) loop_end = region_end - region_start;
	else loop_end = region[r][LOOP_END] - region_start;

	region_bytes = (region_end - region_start) * data_width;
printf("region %d has %d bytes of %d total; using %d\n", r, region_bytes, datasize, total_region_bytes);
printf("\tvolume %f, ampeg_release %f, loop_mode %d\n",
	region_flt[r][VOLUME], region_flt[r][AMPEG_RELEASE], region[r][LOOP_MODE]);

	if (stereo_layer) strcpy(sample.name, "bleahR");
	else if (right_buf) strcpy(sample.name, "bleahL");
	else strcpy(sample.name, "bleahM");
	sample.fractions = 0;
	sample.len = region_bytes;
	sample.loop_start = loop_start * 2;
	sample.loop_end = loop_end * 2;
	sample.base_freq = region_samplerate[r];
	sample.low_note = freq_table[region[r][LOKEY] ];
	sample.high_note = freq_table[region[r][HIKEY] ];
	sample.base_note = freq_table[region[r][PITCH_KEYCENTER] ];
	sample.detune = 512;
	sample.panning = 7;

	sample.tremolo_sweep = 0;
	sample.tremolo_rate = 0;
	sample.tremolo_depth = 0;
	sample.vibrato_sweep = 0;
	sample.vibrato_rate = 0;
	sample.vibrato_depth = 0;
	sample.modes = region_modes[r];
	sample.scale_frequency = region[r][PITCH_KEYCENTER];
	sample.scale_factor = 1024;

	sample.volume = 255;

	make_sample(&sample, r);

	memcpy (buf, (char *) &sample, sizeof (sample));
	fix_sample_write(buf, &sample);

	write(stereofd, buf, sizeof (sample));

  /* wave data */
	if (!stereo_layer)
		write(stereofd, left_buf + data_width * region_start, region_bytes);
	else
		write(stereofd, right_buf + data_width * region_start, region_bytes);

     } /* for each key range */
   } /* for each stereo channel */
  } /* for each vlayer */

}
#endif


