#ifndef STREAM_H_
#define STREAM_H_
#include "main.h"
// Avaiable channels
typedef enum {
CHAN_NONE,
CHAN_CTRL,
CHAN_FM1, CHAN_FM2, CHAN_FM3, CHAN_FM4, CHAN_FM5, CHAN_FM6, CHAN_FMX,
CHAN_PSG1, CHAN_PSG2, CHAN_PSG3, CHAN_PSG4, CHAN_PSGX,
CHAN_PCM1, CHAN_PCM2, CHAN_PCMX,
NUM_CHANNELS
} Channel;
// Possible stream event types
typedef enum {
EVENT_NONE, // (ignore)
EVENT_LOAD, // Load instrument
EVENT_KEYON, // Key-on
EVENT_KEYOFF, // Key-off
EVENT_PITCH, // Set pitch
EVENT_VOLUME, // Set volume
EVENT_PAN, // Set panning
EVENT_TEMPO, // Set tempo
EVENT_FMREG, // FM register write
EVENT_LOOP, // Set loop point
EVENT_LOCK, // Lock channel
EVENT_VMMOVE, // var = value
EVENT_VMADD, // var = var + value
EVENT_VMSUB, // var = var - value
EVENT_VMAND, // var = var AND value
EVENT_VMOR, // var = var OR value
EVENT_VMXOR, // var = var XOR value
EVENT_RAW, // Raw byte
} EventType;
// Data for a single stream event
typedef struct {
EventType type; // Event type
Channel channel; // Affected channel
int arg[4]; // Event arguments
uint64_t timestamp; // Event timestamp in ticks
size_t sort_priority; // Sorting order priority between events
// that have the same timestamp (events with
// lower values are placed earlier)
} Event;
// Data for a whole stream
typedef struct {
Event *events; // Pointer to array of events
size_t num_events; // Number of events in the stream
size_t allocated_events; // Number of allocated slots in the array
uint64_t timestamp; // Current timestamp
uint64_t end_timestamp; // Timestamp at end of stream
unsigned looped: 1; // Set if it loops
} Stream;
Stream *create_stream(void);
Event *create_event(Stream *stream);
void sort_stream(Stream *stream);
void delete_stream(Stream *stream);
//***************************************************************************
// Quick functions to determine if a channel is of a given type.
//---------------------------------------------------------------------------
// Yes, the inline is needed (not for optimization, but because it tells the
// compiler to not complain if a function isn't used despite being static —
// it's either that or turn them into macros)
//***************************************************************************
static inline int is_fm(Channel chan) {
return chan >= CHAN_FM1 && chan <= CHAN_FMX;
}
static inline int is_psg(Channel chan) {
return chan >= CHAN_PSG1 && chan <= CHAN_PSGX;
}
static inline int is_square(Channel chan) {
return is_psg(chan) && chan != CHAN_PSG4;
}
static inline int is_pcm(Channel chan) {
return chan >= CHAN_PCM1 && chan <= CHAN_PCMX;
}
static inline int is_real_chan(Channel chan) {
return is_fm(chan) || is_psg(chan) || is_pcm(chan);
}
#endif