a2bejwld/a2bejwld/mockingboard.h
Jeremy Rand 20ad7dda1c Add code from Total Replay to detect the sound chip automatically on startup. This then leads to a complete rethinking about how to save/load the options for the game. It used to ask what slot the mockingboard was in (if any) and whether it had a speech chip. Now, the game should just know this information. So, I turned the first boolean in the save file into an options file version byte and bumped it to "2". The boolean was always true and was kind of a very simple "magic number" to say that the contents was valid. Now it is a version number of the contents. The slot number and boolean for the speech chip is are now each turned into booleans - one to say whether to enable a mockingboard if found and the other to enable the speech chip if found.
This means there are three booleans in the options related to sound now.  The first one enables/disables sound entirely and is default on.  The second is only relevant if the sound is enabled and says "use a mockingboard if present".  Again this is true by default.  Finally, the this says "use a speech chip on the mockingboard if present" and is only relevant if the mockingboard is also enabled.

So, the basic approach now is to default the "best" sound options and auto-detect the sound HW at launch.  The user can then use the options to downgrade their sound all the way to basic Apple // sound or turn off the sound entirely.
2020-03-04 22:23:09 -05:00

135 lines
4.0 KiB
C

//
// mockingboard.h
// mocktest
//
// Created by Jeremy Rand on 2016-09-10.
// Copyright © 2016 Jeremy Rand. All rights reserved.
//
#ifndef __mocktest__mockingboard__
#define __mocktest__mockingboard__
#include <stdbool.h>
#include <stdint.h>
// Defines
#define MOCK_NUM_CHANNELS 3
#define TONE_PERIOD_C(octave) (0x7a3 >> (octave - 1))
#define TONE_PERIOD_C_SHARP(octave) (0x735 >> (octave - 1))
#define TONE_PERIOD_D(octave) (0x6cd >> (octave - 1))
#define TONE_PERIOD_D_SHARP(octave) (0x66c >> (octave - 1))
#define TONE_PERIOD_E(octave) (0x60f >> (octave - 1))
#define TONE_PERIOD_F(octave) (0x5b8 >> (octave - 1))
#define TONE_PERIOD_F_SHARP(octave) (0x566 >> (octave - 1))
#define TONE_PERIOD_G(octave) (0x518 >> (octave - 1))
#define TONE_PERIOD_G_SHARP(octave) (0x4cf >> (octave - 1))
#define TONE_PERIOD_A(octave) (0x48a >> (octave - 1))
#define TONE_PERIOD_A_SHARP(octave) (0x449 >> (octave - 1))
#define TONE_PERIOD_B(octave) (0x40b >> (octave - 1))
#define MIN_NOISE_PERIOD 0
#define MAX_NOISE_PERIOD 31
#define TONE_CHANNEL_A 1
#define TONE_CHANNEL_B 2
#define TONE_CHANNEL_C 4
#define NOISE_CHANNEL_A 8
#define NOISE_CHANNEL_B 16
#define NOISE_CHANNEL_C 32
#define ENABLE_CHANNEL(channels) (0x3f ^ (channels))
#define ENABLE_ALL_TONE_CHANNELS ENABLE_CHANNEL(TONE_CHANNEL_A|TONE_CHANNEL_B|TONE_CHANNEL_C)
#define ENABLE_ALL_NOISE_CHANNELS ENABLE_CHANNEL(NOISE_CHANNEL_A|NOISE_CHANNEL_B|NOISE_CHANNEL_C)
#define ENABLE_ALL_CHANNELS ENABLE_CHANNEL(TONE_CHANNEL_A|TONE_CHANNEL_B|TONE_CHANNEL_C|NOISE_CHANNEL_A|NOISE_CHANNEL_B|NOISE_CHANNEL_C)
#define MIN_AMPLITUDE 0
#define MAX_AMPLITUDE 15
#define VARIABLE_AMPLITUDE 16
#define MIN_ENVELOPE_PERIOD 0
#define MAX_ENVELOPE_PERIOD 65535u
#define MILLISEC_TO_ENVELOP_PERIOD(ms) ((ms) * 4)
// Here is a table of the envelope shapes and how they look:
//
// ENVELOPE_SHAPE_ONE_SHOT_DECAY \__________...
//
// ENVELOPE_SHAPE_ONE_SHOT_ATTACK /__________...
//
// ENVELOPE_SHAPE_CONT_DECAY \|\|\|\|\|\...
//
// ENVELOPE_SHAPE_CONT_DECAY_HOLD \__________...
//
// ENVELOPE_SHAPE_CONT_DECAY_ALT \/\/\/\/\/\...
// _________
// ENVELOPE_SHAPE_CONT_DECAY_ALT_HOLD \| ...
//
// ENVELOPE_SHAPE_CONT_ATTACK /|/|/|/|/|/...
// __________
// ENVELOPE_SHAPE_CONT_ATTACK_HOLD / ...
// ENVELOPE_SHAPE_CONT_ATTACK_ALT /\/\/\/\/\/...
//
// ENVELOPE_SHAPE_CONT_ATTACK_ALT_HOLD /|_________...
#define ENVELOPE_SHAPE_ONE_SHOT_DECAY 0
#define ENVELOPE_SHAPE_ONE_SHOT_ATTACK 4
#define ENVELOPE_SHAPE_CONT_DECAY 8
#define ENVELOPE_SHAPE_CONT_DECAY_HOLD 9
#define ENVELOPE_SHAPE_CONT_DECAY_ALT 10
#define ENVELOPE_SHAPE_CONT_DECAY_ALT_HOLD 11
#define ENVELOPE_SHAPE_CONT_ATTACK 12
#define ENVELOPE_SHAPE_CONT_ATTACK_HOLD 13
#define ENVELOPE_SHAPE_CONT_ATTACK_ALT 14
#define ENVELOPE_SHAPE_CONT_ATTACK_ALT_HOLD 15
// Typedefs
typedef uint8_t tSlot;
typedef enum {
SPEAKER_NONE = 0,
SPEAKER_LEFT = (1 << 0),
SPEAKER_RIGHT = (1 << 1),
SPEAKER_BOTH = (1 << 0) | (1 << 1)
} tMockingBoardSpeaker;
typedef struct tMockingSoundRegisters {
uint16_t tonePeriod[MOCK_NUM_CHANNELS];
uint8_t noisePeriod;
uint8_t enable;
uint8_t amplitude[MOCK_NUM_CHANNELS];
uint16_t envelopePeriod;
uint8_t envelopeShape;
uint8_t dummy1;
uint8_t dummy2;
} tMockingSoundRegisters;
// API
extern bool mockingBoardInit(void);
extern void mockingBoardShutdown(void);
extern tSlot mockingBoardSlot(void);
extern void mockingBoardPlaySound(tMockingBoardSpeaker speaker, tMockingSoundRegisters *registers);
extern void mockingBoardStopSound(tMockingBoardSpeaker speaker);
extern bool mockingBoardHasSpeechChip(void);
extern bool mockingBoardSpeechIsBusy(void);
extern bool mockingBoardSpeechIsPlaying(void);
extern bool mockingBoardSpeak(uint8_t *data, uint16_t dataLen);
#endif /* defined(__mocktest__mockingboard__) */