/*
 * $Id: midilib.h,v 1.41 1998/06/04 05:33:26 keithp Exp $
 *
 * Copyright © 1998 Keith Packard
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Keith Packard not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Keith Packard makes no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef _GSI__gsimidi_pcm__gsikpmidi_h
#define _GSI__gsimidi_pcm__gsikpmidi_h

#ifdef _cplusplus
extern "C" {
#endif /* __cplusplus */

/* WHS: removed: #define _POSIX_C_SOURCE 2 */

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

//#include "midipatch.h"
#include <gsi/kpmidi_patch.h>
//#include "debug.h"

//#define TRUE  1
//#define FALSE 0
#include <gsi/whs_types.h>
typedef int Boolean;

#define MIDI_VOICES	64

#define VOLUME_BITS	8

#define NUM(a)	(sizeof (a) / sizeof ((a)[0]))

extern const float	volumeTable[1 << VOLUME_BITS];
extern const double	equal440Table[12];
extern const double	equal415Table[12];
extern const double	mean415Table[12];
extern const double	werk3Table[12];
extern const double	vallottiTable[12];

#define NOTE_TABLE_BASE	    69	    /* A440 index in equal440 table */

extern double		noteTable[128];
extern const double	centsTable[100];
extern const double	semiTable[128];

#define SINE_BITS	9

extern const double	sineTable[1<<SINE_BITS];

extern MidiPatch	sample_instruments[];
extern int		sample_ninstruments;

#define EnvelopeVolumeIndex(e)	((e) >> (31 - VOLUME_BITS))
#define EnvelopeVolume(e)  volumeTable[EnvelopeVolumeIndex(e)]

typedef uint32		MidiSine;

#define SineValue(v)	(sineTable[(v) >> (32 - SINE_BITS)])

typedef uint32		MidiFix;

#define MAX_MIDI_SAMPLES    131072
#define FIX_INT		17	    /* log2(MAX_MIDI_SAMPLES) */
#define FIX_FRACTION	15	    /* fraction bits (32 - FIX_INT) */
#define FIX_MASK	0x7fff
#define FixToInt(f)	((int) ((f) >> FIX_FRACTION))
#define FixFromInt(i)	(((MidiFix) (i)) << FIX_FRACTION)
#define FixIntPart(f)	((f) & ~FIX_MASK)
#define FixFracPart(f)	((f) & FIX_MASK)

#define INTERP_BITS	6
#define INTERP_MASK	((1 << INTERP_BITS) - 1)

extern const float	midiInterp[1 << INTERP_BITS];

#define FixToInterp(f)	(((f) >> (FIX_FRACTION-INTERP_BITS)) & INTERP_MASK)
#define FixToFloor(f)	midiInterp[FixToInterp(f)]
#define FixToCeil(f)	(1.0f - midiInterp[FixToInterp(f)])

enum { NOTE_OFF = 8, NOTE_ON, AFTER_TOUCH, CONTROL_CHANGE, PROGRAM_CHANGE,
    CHANNEL_PRESSURE, PITCH_WHEEL, SYSEX };

typedef struct _voiceWave {
    MidiFix	    sample;
    MidiFix	    sampleStep;	/* wave sample step per output sample */
    MidiFix	    end;	/* something happens here */
    MidiFix	    loop_len;	/* loop is this long */
    MidiFix	    data_end;	/* end of sample */
    Boolean	    loopRelease;/* use loop during release */
    double	    freqFactor;	/* sample rate conversion factor */
    const float	    *samples;	/* samples */
} VoiceWave;

/*
 * Envelope values stored using this rate
 */

#define ENVELOPE_RATE	44100

typedef struct _voiceEnvelope {
    float	    fLeft;
    float	    fRight;
    float	    fValue;
    float	    fPan;
    float	    fTrem;
    int		    remain;	/* samples until next segment */
    int32	    valueStep;	/* envel value step per output sample */
    int32	    value;	/* current envelope value */
    int32	    target;	/* goal value for envelope element */
    Boolean	    on;		/* voice sounding */
    int		    element;	/* index into array of envelope values */
    double	    envelopeRatio; /* ENVELOPE_RATE / output envelopeRate */
    float    	    volume;	/* velocity * channel volume in range 0-1 */
    float	    in_scale;	/* instrument scale factor */
    float	    mult;	/* envelope scale factor (scale * volume) */
} VoiceEnvelope;
    
typedef struct _voiceLFO {
    MidiSine	    value;
    MidiSine	    step;
    float	    scale;
} VoiceLFO;

#define MAX_PHASE   64

#define voiceDelay(v,i)    v->delay[(i) & (MAX_PHASE-1)]

typedef struct _midiVoice {
    /*
     * Assigned at NOTE_ON
     */
    unsigned char	channel;
    unsigned char	note;
    unsigned char	on;
    unsigned char	velocity;
    const Instrument	*instrument;
    const MidiPatch	*patch;
    const SampleElement	*se;

    /*
     * Computed while note plays
     */
    VoiceWave		wave;
    VoiceEnvelope	envelope;
    VoiceLFO		tremelo;
    VoiceLFO		vibrato;

    /*
     * phase shift
     */
    float	    delay[MAX_PHASE];
    int		    phase;
    int		    delay_pos;
} MidiVoice;

extern const char	    *patchNames[128];

#define MIN_DRUM    35
#define MAX_DRUM    81

extern const char	    *drumNames[MAX_DRUM-MIN_DRUM+1];

#define MIDI_CHANNELS	16

#define MIDI_DEFAULT_PAN_PHASE	0.005
#define MIDI_VOLUME_SCALE	(8192.0f)

typedef struct _midiChannel {
    unsigned char   program;
    unsigned char   volume;
    unsigned char   expression;
    unsigned char   pan;
    unsigned char   sustain;
    unsigned char   drum;
    unsigned short  bend;
    unsigned char   bend_semi;
    unsigned char   bend_cent;
    unsigned char   modulation;
    unsigned char   chorus;
    int		    bend_range;
    double	    bend_ratio;
    int		    pn_registered;
    unsigned char   pn_r_msb;
    unsigned char   pn_r_lsb;
    unsigned char   pn_u_msb;
    unsigned char   pn_u_lsb;
} MidiChannel;

typedef enum _MidiText {
    MidiTextText = 1,
    MidiTextCopyright,
    MidiTextSequence,
    MidiTextInstrument,
    MidiTextLyric,
    MidiTextMarker,
    MidiTextCue
} MidiText;

typedef struct _midiFormat {
    unsigned short  xor;
    int		    l_msb;
    int		    l_lsb;
    int		    r_msb;
    int		    r_lsb;
    int		    stereo;
} MidiFormat;

typedef struct _midiReverb {
    float	    left;
    float	    right;
} MidiReverb;

typedef struct _midiReverbTap {
    float	    amount;
    unsigned long   offset;
} MidiReverbTap;

typedef struct _midiData {
    /*
     * Midi source data 
     */
    void	    *source;
    struct _SourceFuncs	*sourceFuncs;

    /*
     * Audio output format
     */
    int		    dataRate;
    int		    stereo;

    int		    envelopeRate;
    int		    envelopeDiv;

    int		    dataBytesPerSample;
    int		    dataBytesPerUnit;	/* bytes per sample * channels */
    MidiFormat	    format;

    int		    bufSamples;
    int		    maxVoices;

    /*
     * output queue
     */
    int		    put;
    int		    get;
    int		    queued;
    unsigned char   *buf;
    int		    syncQueue;	    /* no asynchronous queuing */

    /*
     * Midi state
     */
    int		    done;
    int		    midiDone;
    int		    nactive;
    int		    stopped;
    int		    paused;
    int		    divisions;
    int		    envelopeStep;
    int		    auto_pan;	    /* dynamic per-note pan */
    int		    chorus;
    float	    panPhase;
    double	    eventTime;	    /* tick position of next event */
    double	    time;	    /* current tick position */
    double	    midiSpeedFactor;
    double	    midiSpeed;	    /* ticks per sample */
    double	    gain;	    /* output device gain */
    double	    lengthSeconds;  /* total song length in seconds */
    unsigned long   samples;	    /* current song position in samples */
    unsigned long   tempo;
    float	    scale;
    MidiVoice	    *voices;
    MidiChannel	    channels[MIDI_CHANNELS];
    MidiReverb	    *reverb;
    MidiReverbTap   *reverbTaps;
    char	    *reverbName;
    int		    reverbCount;
    unsigned long   reverbPos;
    unsigned long   reverbMask;

    /*
     * instrument data
     */
    const MidiMap   *map;
    const MidiPatch *patchMap[128];
    const MidiPatch *drumMap[MAX_DRUM-MIN_DRUM+1];
    char	    *patchFile;
} MidiData;

typedef enum _MidiState {
    midiStart,
    midiRunning,
    midiNoteOff,
    midiNoteOn,
    midiAfterTouch,
    midiControlChange,
    midiPitchWheel,
    midiSysex,
    midiSysexUniversalNonRealTime,
    midiSysexTuningNRT,
    midiSysexTuningBulkReplyMore,
    midiSysexTuningBulkReply,
    midiSysexUniversalRealTime,
    midiSysexDeviceControl,
    midiSysexTuningRT,
    midiSysexTuningRTNoteChange,
    midiSysexTuningRTNoteChangeMoreCont,
    midiSysexTuningRTNoteChangeMore,
    midiSysexFile,
    midiSysexFileMore,
    midiInt,
    midiIntMore,
    midiBufSome,
    midiSkipSome,
    midiSkip,
    midiEOF,
} MidiState;

typedef struct _MidiParseState {
    MidiState	    state;	    /* current parser state */
    MidiState	    returnState;    /* single element state stack */
    unsigned char   status;	    /* current running status */
    int		    value;	    /* general value */
    int		    count;	    /* counter, counts up to limit */
    int		    limit;
    Boolean	    obeyRealtime;   /* look for and parse System Realtime */
    unsigned char   buf[4];	    /* temporary storage */
} MidiParseState;

typedef struct _SourceFuncs {
    int		    (*Read) (MidiData *, char *);
    int		    (*Event) (MidiData *, Boolean);
    void	    (*Dispose) (MidiData *);
    void	    (*Reset) (MidiData *);
    int		    (*Sample) (MidiData *, char *);
} SourceFuncs;

extern SourceFuncs  MidiFileSource;
extern SourceFuncs  MidiInSource;


void	voiceWaveInit (MidiData		*d,
		       MidiVoice	*v,
		       double		frequency,
		       Boolean		loopRelease,
		       float		pan);

#define voiceWaveChange(vw,freq)    ((vw)->sampleStep = (MidiFix) ((freq) * (vw)->freqFactor))

double	VoiceVolume (MidiData *d, int voice);
double	VoiceFrequency (MidiData *d, int voice);

Boolean	voiceEnvelopeInit (MidiData	    *d,
			   MidiVoice	    *v,
			   float	    volume,
			   float	    in_scale,
			   float	    pan);

void	voiceLFOInit (VoiceLFO	    *vl,
		      int32	    frequency,
		      unsigned long envelopeRate,
		      double	    scale);

void	voiceIdle (MidiData *d, int voice);

#define Volume(vel,vol,exp)    (((vel)*(vol)*(exp + 127)) / (127.0*127.0*254.0))

void	voicePress (MidiData	    *d,
		    int		    voice,
		    const MidiPatch *patch,
		    float	    volume,
		    float	    in_scale,
		    double	    frequency,
		    float	    pan);

void	voiceRelease (MidiData	    *d,
		      int	    voice,
		      int	    velocity);

void	voiceBend (MidiData	    *d,
		   int		    voice,
		   double	    frequency,
		   unsigned long    sampleRate);


void	voiceVolume (MidiData	    *d,
		     int	    voice);

void
voiceLFOChange (VoiceLFO	*vl,
		int32		frequency,
		unsigned long	envelopeRate,
		float		scale);

void
voiceLFOInit (VoiceLFO	    *vl,
	      int32	    frequency,
	      unsigned long envelopeRate,
	      double	    scale);
    
#define interpValue(s,f)	((s)[FixToInt(f)] * FixToFloor(f) + \
				 (s)[FixToInt(f)+1] * FixToCeil(f))
#define nearValue(s,f)		((s)[FixToInt(f)])

#define voiceWaveValueI(vw)	    interpValue((vw)->samples, (vw)->sample)
#define voiceWaveValueN(vw)	    nearValue((vw)->samples, (vw)->sample)
#define voiceEnvelopeValue(ve)	    (EnvelopeVolume((ve)->value) * \
				     (ve)->mult * (ve)->fTrem)

void	MidiOutInit (MidiData *);
void	MidiParse (MidiData *, char *s, int len);
int	MidiParseOne (MidiData *, MidiParseState *, unsigned char *, int, Boolean);
int	MidiParseInt (unsigned char *buf, unsigned long *i);
void	MidiAllNotesOff (MidiData *);

int	MidiSample (MidiData *, char *);
void	MidiQueue (MidiData *, int amount);

void	MidiSetFormat (MidiData *, Boolean sixteenBit, 
		       Boolean unsign, Boolean msbFirst, 
		       Boolean stereo, Boolean leftFirst);
Boolean	InitMidiPatch (MidiData *);
void	FreeMidiPatch (MidiData *);
void	SaveMidiVolumes (void);
void	InitMidiVolumes (void);

int	MidiInit (MidiData *);
void	MidiSetDefaults (MidiData *);
double	MidiSeek (MidiData *, double usec);
void	MidiReset (MidiData *);

int	MidiSetFile (MidiData *, char *);
void	MidiDispose (MidiData *);
void	MidiFini (MidiData *);
void	MidiClose (MidiData *);
void	MidiSetTuning (const double [12]);
Boolean	MidiSetTemperment (char *temperment);
void	MidiChangeTuning (MidiData *, int note, int base, int cents);
void	MidiChangePanPhase (MidiData *, float panPhase);
void	MidiSetNote (int note, const double table[12], int base, int cents);

void
MidiNoteOn (MidiData	    *d,
	    unsigned char   channel,
	    unsigned char   note,
	    unsigned char   velocity,
	    Boolean	    seek);

void
MidiNoteOff (MidiData	    *d,
	     unsigned char  channel,
	     unsigned char  note,
	     unsigned char  velocity);


/* Low level midi/synth functions */
void MidiComputeBend (MidiData *d, unsigned char channel);
void MidiComputeTremelo (MidiData *d, unsigned char channel);
void MidiComputeVibrato (MidiData *d, unsigned char channel);
void MidiSetBendRange (MidiData *d, unsigned char channel);
void MidiChangeVolume (MidiData *d, unsigned char channel);
void MidiResetControllers (MidiData *d, int channel);

/* Low level midi parsing */
void MidiInitState (MidiParseState *s);

const MidiPatch	*MidiPatchParse (const char *);
const MidiPatch	*MidiPatchMap (const char *);
const MidiPatch	*ReadGUSPatch (const char *);

const MidiPatch *MidiLoadDrum (MidiData *d, unsigned char note);
const MidiPatch *MidiLoadProgram (MidiData *d, unsigned char program);

int	PatchWrite (const char	    *patch,
		    const MidiMap   *map,
		    Boolean	    writeInstruments,
		    Boolean	    writeBinary);

int
InstrumWriteBinary (const MidiPatch	*p,
		    const float		scale,
		    const char		*prefix, 
		    const char		*file);

int
InstrumWriteText (const MidiPatch   *p,
		  const float	    scale, 
		  const char	    *prefix, 
		  const char	    *file);

FILE	*OpenMidiVolumes (char *mode);
void	InitMidiVolumes (void);
void	SaveMidiVolumes (void);

void	MidiError (char *, ...);

/* string match functions */
const char  *match_next (const char *a, char *part);
int	    match_any (const char *a, const char *b);



/*
 * Required UI API (events showing what's changing in the playing)
 */
void	UiStart (MidiData *);
void    UiClose (MidiData *d);
//void	UiUpdate (MidiData *d); /* flush ?*/

void	UiSetText (MidiData *, int channel, char *text, MidiText type);
void	UiSetTime (MidiData *, int num, int den);
void	UiSetKey (MidiData *, int sig, int mode);
void	UiProgramChange (MidiData *, int channel, int program);

void	UiNoteOn (MidiData *d, int channel, int note);
void	UiNoteOff (MidiData *d, int channel, int note);
void	UiNoteIdle (MidiData *d, int channel, int note);

void	UiSetChannelVolume (MidiData *d, int channel);
void	UiSetTempo (MidiData *d);

void	UiError (char *);



#define SAMPLE_RATE 44100
#define BYTES_PER_SAMPLE    2
float	patchVolume[128];
float	drumVolume[81-35+1];

#ifdef _cplusplus
}
#endif /* __cplusplus */

#endif /* _GSI__gsimidi_pcm__gsikpmidi_h */
