Add mockingboard library and start reworking the sound code to prepare to integrate it.
This commit is contained in:
parent
7e7d34a878
commit
36ed166670
|
@ -12,6 +12,9 @@
|
|||
9D4D1AB31D6D709600D20BB8 /* game.c in Sources */ = {isa = PBXBuildFile; fileRef = 9D6B47401D40098300F6D704 /* game.c */; };
|
||||
9D4D1AB41D6D709F00D20BB8 /* machine.c in Sources */ = {isa = PBXBuildFile; fileRef = 9D4D1AA31D6D0E9B00D20BB8 /* machine.c */; };
|
||||
9D4D1AB51D6D70A300D20BB8 /* anim.c in Sources */ = {isa = PBXBuildFile; fileRef = 9D6B47481D4270EC00F6D704 /* anim.c */; };
|
||||
9DB20B3E1E078FE20065E263 /* mockingboard.c in Sources */ = {isa = PBXBuildFile; fileRef = 9DB20B3A1E078FE20065E263 /* mockingboard.c */; };
|
||||
9DB20B3F1E078FE20065E263 /* mockingboard_speech.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DB20B3C1E078FE20065E263 /* mockingboard_speech.s */; };
|
||||
9DB20B421E07904A0065E263 /* sound.c in Sources */ = {isa = PBXBuildFile; fileRef = 9DB20B401E07904A0065E263 /* sound.c */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
|
@ -58,6 +61,12 @@
|
|||
9D6B47491D4270EC00F6D704 /* anim.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = anim.h; sourceTree = "<group>"; };
|
||||
9D6B474A1D42DEB600F6D704 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||
9D6B474C1D43BBAC00F6D704 /* a2bejwld.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = a2bejwld.png; sourceTree = "<group>"; };
|
||||
9DB20B3A1E078FE20065E263 /* mockingboard.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mockingboard.c; sourceTree = "<group>"; };
|
||||
9DB20B3B1E078FE20065E263 /* mockingboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mockingboard.h; sourceTree = "<group>"; };
|
||||
9DB20B3C1E078FE20065E263 /* mockingboard_speech.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = mockingboard_speech.s; sourceTree = "<group>"; };
|
||||
9DB20B3D1E078FE20065E263 /* mockingboard_speech.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mockingboard_speech.h; sourceTree = "<group>"; };
|
||||
9DB20B401E07904A0065E263 /* sound.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sound.c; sourceTree = "<group>"; };
|
||||
9DB20B411E07904A0065E263 /* sound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sound.h; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -125,7 +134,10 @@
|
|||
9D4D1AA41D6D0E9B00D20BB8 /* machine.h */,
|
||||
9D6B47481D4270EC00F6D704 /* anim.c */,
|
||||
9D6B47491D4270EC00F6D704 /* anim.h */,
|
||||
9DB20B401E07904A0065E263 /* sound.c */,
|
||||
9DB20B411E07904A0065E263 /* sound.h */,
|
||||
9D6B472F1D3FB16F00F6D704 /* Makefile */,
|
||||
9DB20B391E078FC70065E263 /* Mockingboard */,
|
||||
9D3A9FBE1D457973004C5897 /* joystick */,
|
||||
9D3A9FBA1D4578B4004C5897 /* mouse */,
|
||||
9D6B47301D3FB16F00F6D704 /* make */,
|
||||
|
@ -156,6 +168,17 @@
|
|||
name = screenshots;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9DB20B391E078FC70065E263 /* Mockingboard */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9DB20B3A1E078FE20065E263 /* mockingboard.c */,
|
||||
9DB20B3B1E078FE20065E263 /* mockingboard.h */,
|
||||
9DB20B3C1E078FE20065E263 /* mockingboard_speech.s */,
|
||||
9DB20B3D1E078FE20065E263 /* mockingboard_speech.h */,
|
||||
);
|
||||
name = Mockingboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXLegacyTarget section */
|
||||
|
@ -233,9 +256,12 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
9D4D1AB51D6D70A300D20BB8 /* anim.c in Sources */,
|
||||
9DB20B421E07904A0065E263 /* sound.c in Sources */,
|
||||
9DB20B3E1E078FE20065E263 /* mockingboard.c in Sources */,
|
||||
9D4D1AB31D6D709600D20BB8 /* game.c in Sources */,
|
||||
9D4D1AB11D6D708E00D20BB8 /* main.c in Sources */,
|
||||
9D4D1AB21D6D709100D20BB8 /* ui.c in Sources */,
|
||||
9DB20B3F1E078FE20065E263 /* mockingboard_speech.s in Sources */,
|
||||
9D4D1AB41D6D709F00D20BB8 /* machine.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -371,6 +397,7 @@
|
|||
9D4D1AB01D6D704800D20BB8 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
9D6B472B1D3FB16F00F6D704 /* Build configuration list for PBXProject "a2bejwld" */ = {
|
||||
isa = XCConfigurationList;
|
||||
|
|
|
@ -31,7 +31,7 @@ PGM=a2bejwld
|
|||
# MACHINE = apple2enh
|
||||
# MACHINE = apple2enh-dos33
|
||||
MACHINE = apple2enh-system
|
||||
* MACHINE = apple2enh-loader
|
||||
# MACHINE = apple2enh-loader
|
||||
# MACHINE = apple2enh-reboot
|
||||
|
||||
# Uncomment and set this to your starting address in Apple II memory
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "dbllores.h"
|
||||
#include "game.h"
|
||||
#include "machine.h"
|
||||
#include "sound.h"
|
||||
#include "ui.h"
|
||||
|
||||
|
||||
|
@ -28,13 +29,6 @@
|
|||
|
||||
#define DROP_ACCELERATION 1
|
||||
|
||||
#define CLEAR_GEM_SOUND_NORMAL 0
|
||||
#define CLEAR_GEM_SOUND_STAR 1
|
||||
#define CLEAR_GEM_SOUND_SPECIAL 2
|
||||
#define CLEAR_GEM_SOUND_EXPLODE 3
|
||||
#define NUM_CLEAR_GEM_SOUNDS 4
|
||||
|
||||
|
||||
#define VERTICAL_PIXELS 48
|
||||
#define HORIZONTAL_PIXELS 64
|
||||
|
||||
|
@ -70,7 +64,6 @@ typedef struct tStarAnimState
|
|||
typedef struct tClearGemAnimState
|
||||
{
|
||||
uint8_t squaresToClear[NUM_SQUARES / (sizeof(uint8_t))];
|
||||
uint8_t clearGemSound;
|
||||
bool gotOne;
|
||||
} tClearGemAnimState;
|
||||
|
||||
|
@ -105,28 +98,6 @@ static uint8_t gTempX;
|
|||
static uint8_t gTempY;
|
||||
static uint8_t gTempGemType;
|
||||
|
||||
static uint8_t gClearGemSoundFreq[NUM_CLEAR_GEM_SOUNDS][8] = {
|
||||
{ // CLEAR_GEM_SOUND_NORMAL
|
||||
30, 25, 20, 30, 30, 30, 30, 0 },
|
||||
{ // CLEAR_GEM_SOUND_STAR
|
||||
10, 9, 8, 7, 6, 5, 4, 0 },
|
||||
{ // CLEAR_GEM_SOUND_SPECIAL
|
||||
4, 6, 8, 10, 8, 6, 4, 0 },
|
||||
{ // CLEAR_GEM_SOUND_EXPLODE
|
||||
50, 60, 50, 60, 50, 60, 50, 0 }
|
||||
};
|
||||
|
||||
static uint8_t gClearGemSoundDuration[NUM_CLEAR_GEM_SOUNDS][8] = {
|
||||
{ // CLEAR_GEM_SOUND_NORMAL
|
||||
10, 15, 20, 10, 10, 10, 10, 0 },
|
||||
{ // CLEAR_GEM_SOUND_STAR
|
||||
30, 31, 32, 33, 34, 35, 36, 0 },
|
||||
{ // CLEAR_GEM_SOUND_SPECIAL
|
||||
36, 34, 32, 30, 32, 34, 36, 0 },
|
||||
{ // CLEAR_GEM_SOUND_EXPLODE
|
||||
8, 8, 8, 8, 8, 8, 8, 0 },
|
||||
};
|
||||
|
||||
static tClearGemHandler gClearGemHandler[] = {
|
||||
explodeGemFrame1,
|
||||
explodeGemFrame2,
|
||||
|
@ -213,6 +184,7 @@ void doStarAnim(void)
|
|||
void beginClearGemAnim(void)
|
||||
{
|
||||
memset(&gClearGemAnimState, 0, sizeof(gClearGemAnimState));
|
||||
beginClearGemSound();
|
||||
}
|
||||
|
||||
|
||||
|
@ -235,50 +207,22 @@ void undoClearAtSquare(tSquare square)
|
|||
}
|
||||
|
||||
|
||||
void playSoundForExplodingGem(void)
|
||||
{
|
||||
if (gClearGemAnimState.clearGemSound < CLEAR_GEM_SOUND_EXPLODE)
|
||||
gClearGemAnimState.clearGemSound = CLEAR_GEM_SOUND_EXPLODE;
|
||||
}
|
||||
|
||||
|
||||
void playSoundForStarringGem(void)
|
||||
{
|
||||
if (gClearGemAnimState.clearGemSound < CLEAR_GEM_SOUND_STAR)
|
||||
gClearGemAnimState.clearGemSound = CLEAR_GEM_SOUND_STAR;
|
||||
}
|
||||
|
||||
|
||||
void playSoundForSpecialGem(void)
|
||||
{
|
||||
if (gClearGemAnimState.clearGemSound < CLEAR_GEM_SOUND_SPECIAL)
|
||||
gClearGemAnimState.clearGemSound = CLEAR_GEM_SOUND_SPECIAL;
|
||||
}
|
||||
|
||||
|
||||
#undef DEBUG_CLEAR_ANIM
|
||||
void endClearGemAnim(void)
|
||||
{
|
||||
tSquare square;
|
||||
uint8_t bit;
|
||||
uint8_t offset;
|
||||
uint8_t *clearGemSoundFreq;
|
||||
uint8_t *clearGemSoundDuration;
|
||||
uint8_t frame;
|
||||
|
||||
if (!gClearGemAnimState.gotOne)
|
||||
return;
|
||||
|
||||
clearGemSoundFreq = &(gClearGemSoundFreq[gClearGemAnimState.clearGemSound][0]);
|
||||
clearGemSoundDuration = &(gClearGemSoundDuration[gClearGemAnimState.clearGemSound][0]);
|
||||
|
||||
for (frame = 0; frame < (sizeof(gClearGemHandler) / sizeof(gClearGemHandler[0])); frame++) {
|
||||
bit = 1;
|
||||
offset = 0;
|
||||
|
||||
playSound(*clearGemSoundFreq, *clearGemSoundDuration);
|
||||
clearGemSoundFreq++;
|
||||
clearGemSoundDuration++;
|
||||
playClearGemSound(frame);
|
||||
|
||||
gVblWait();
|
||||
for (square = 0; square < NUM_SQUARES; square++) {
|
||||
|
@ -491,7 +435,7 @@ void endDropAnim(void)
|
|||
|
||||
if (gemInfo->y == gemInfo->endY) {
|
||||
gemInfo->landed = true;
|
||||
playSound(1, 1);
|
||||
playLandingSound();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -603,4 +547,4 @@ void endDropAnim(void)
|
|||
cgetc();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,6 @@ extern void doStarAnim(void);
|
|||
extern void beginClearGemAnim(void);
|
||||
extern void addClearAtSquare(tSquare square);
|
||||
extern void undoClearAtSquare(tSquare square);
|
||||
extern void playSoundForExplodingGem(void);
|
||||
extern void playSoundForStarringGem(void);
|
||||
extern void playSoundForSpecialGem(void);
|
||||
extern void endClearGemAnim(void);
|
||||
|
||||
extern void swapSquares(tSquare square1, tGemType gemType1, bool starred1,
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
//
|
||||
// mockingboard.c
|
||||
// mocktest
|
||||
//
|
||||
// Created by Jeremy Rand on 2016-09-10.
|
||||
// Copyright © 2016 Jeremy Rand. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mockingboard.h"
|
||||
#include "mockingboard_speech.h"
|
||||
|
||||
|
||||
// Defines
|
||||
|
||||
#define LATCH_COMMAND 0x7
|
||||
#define WRITE_COMMAND 0x6
|
||||
#define RESET_COMMAND 0x0
|
||||
#define THROUGH_PORT_B 0x4
|
||||
|
||||
#define MOCKINGBOARD_LATCH(soundChip) writeCommand((soundChip), LATCH_COMMAND)
|
||||
#define MOCKINGBOARD_WRITE(soundChip) writeCommand((soundChip), WRITE_COMMAND)
|
||||
#define MOCKINGBOARD_RESET(soundChip) writeCommand((soundChip), RESET_COMMAND)
|
||||
|
||||
|
||||
// Typedefs
|
||||
|
||||
typedef enum {
|
||||
SOUND_CHIP_1 = 0,
|
||||
SOUND_CHIP_2 = 1,
|
||||
NUM_SOUND_CHIPS = 2
|
||||
} tMockingBoardSoundChip;
|
||||
|
||||
|
||||
// Globals
|
||||
|
||||
// Addresses for the two 6522's (assuming slot 4 for now)
|
||||
static uint8_t *gMockPortB[NUM_SOUND_CHIPS] = { (uint8_t *)0xc000, (uint8_t *)0xc080 };
|
||||
static uint8_t *gMockPortA[NUM_SOUND_CHIPS] = { (uint8_t *)0xc001, (uint8_t *)0xc081 };
|
||||
static uint8_t *gMockDataDirB[NUM_SOUND_CHIPS] = { (uint8_t *)0xc002, (uint8_t *)0xc082 };
|
||||
static uint8_t *gMockDataDirA[NUM_SOUND_CHIPS] = { (uint8_t *)0xc003, (uint8_t *)0xc083 };
|
||||
|
||||
static uint8_t gMockingBoardInitialized = false;
|
||||
static uint8_t gMockingBoardSpeechInitialized = false;
|
||||
|
||||
|
||||
// Implementation
|
||||
|
||||
static uint8_t *mapIOPointer(tSlot slot, uint8_t *ptr)
|
||||
{
|
||||
uint16_t temp1 = (uint16_t)ptr;
|
||||
uint16_t temp2 = slot;
|
||||
|
||||
temp2 <<= 8;
|
||||
temp1 &= 0xf0ff;
|
||||
|
||||
temp1 |= temp2;
|
||||
ptr = (uint8_t *)temp1;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
void mockingBoardInit(tSlot slot, bool hasSpeechChip)
|
||||
{
|
||||
tMockingBoardSoundChip soundChip;
|
||||
|
||||
if (sizeof(tMockingSoundRegisters) != 16) {
|
||||
printf("The sound registers must be 16 bytes long!\n");
|
||||
}
|
||||
|
||||
for (soundChip = SOUND_CHIP_1; soundChip < NUM_SOUND_CHIPS; soundChip++) {
|
||||
gMockPortB[soundChip] = mapIOPointer(slot, gMockPortB[soundChip]);
|
||||
gMockPortA[soundChip] = mapIOPointer(slot, gMockPortA[soundChip]);
|
||||
gMockDataDirB[soundChip] = mapIOPointer(slot, gMockDataDirB[soundChip]);
|
||||
gMockDataDirA[soundChip] = mapIOPointer(slot, gMockDataDirA[soundChip]);
|
||||
|
||||
*(gMockDataDirA[soundChip]) = 0xff; // Set port A for output
|
||||
*(gMockDataDirB[soundChip]) = 0x7; // Set port B for output
|
||||
}
|
||||
|
||||
if (hasSpeechChip) {
|
||||
if (gMockingBoardSpeechInitialized) {
|
||||
mockingBoardSpeechShutdown();
|
||||
}
|
||||
mockingBoardSpeechInit(slot);
|
||||
gMockingBoardSpeechInitialized = true;
|
||||
} else if (gMockingBoardSpeechInitialized) {
|
||||
mockingBoardSpeechShutdown();
|
||||
gMockingBoardSpeechInitialized = false;
|
||||
}
|
||||
|
||||
gMockingBoardInitialized = true;
|
||||
}
|
||||
|
||||
|
||||
void mockingBoardShutdown(void)
|
||||
{
|
||||
if (gMockingBoardSpeechInitialized) {
|
||||
mockingBoardSpeechShutdown();
|
||||
gMockingBoardSpeechInitialized = false;
|
||||
}
|
||||
|
||||
gMockingBoardInitialized = false;
|
||||
}
|
||||
|
||||
|
||||
static void writeCommand(tMockingBoardSoundChip soundChip, uint8_t command)
|
||||
{
|
||||
volatile uint8_t *ptr = gMockPortB[soundChip];
|
||||
|
||||
*ptr = command;
|
||||
*ptr = THROUGH_PORT_B;
|
||||
}
|
||||
|
||||
|
||||
static void mockingBoardTableAccess(tMockingBoardSoundChip soundChip, tMockingSoundRegisters *registers)
|
||||
{
|
||||
uint8_t *data = (uint8_t *)registers;
|
||||
volatile uint8_t *ptr = gMockPortA[soundChip];
|
||||
uint8_t index;
|
||||
|
||||
if (!gMockingBoardInitialized)
|
||||
return;
|
||||
|
||||
MOCKINGBOARD_RESET(soundChip);
|
||||
for (index = 0; index < 16; index++) {
|
||||
*ptr = index;
|
||||
MOCKINGBOARD_LATCH(soundChip);
|
||||
*ptr = *data;
|
||||
MOCKINGBOARD_WRITE(soundChip);
|
||||
data++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mockingBoardPlaySound(tMockingBoardSpeaker speaker, tMockingSoundRegisters *registers)
|
||||
{
|
||||
if ((speaker & SPEAKER_LEFT) != 0) {
|
||||
mockingBoardTableAccess(SOUND_CHIP_1, registers);
|
||||
}
|
||||
|
||||
if ((speaker & SPEAKER_RIGHT) != 0) {
|
||||
mockingBoardTableAccess(SOUND_CHIP_2, registers);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mockingBoardStopSound(tMockingBoardSpeaker speaker)
|
||||
{
|
||||
if ((speaker & SPEAKER_LEFT) != 0) {
|
||||
MOCKINGBOARD_RESET(SOUND_CHIP_1);
|
||||
}
|
||||
|
||||
if ((speaker & SPEAKER_RIGHT) != 0) {
|
||||
MOCKINGBOARD_RESET(SOUND_CHIP_2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool mockingBoardSpeechIsBusy(void)
|
||||
{
|
||||
return (mockingBoardSpeechBusy != 0);
|
||||
}
|
||||
|
||||
|
||||
bool mockingBoardSpeechIsPlaying(void)
|
||||
{
|
||||
return (mockingBoardSpeechPlaying != 0);
|
||||
}
|
||||
|
||||
|
||||
bool mockingBoardSpeak(uint8_t *data, uint16_t dataLen)
|
||||
{
|
||||
if (!gMockingBoardSpeechInitialized)
|
||||
return false;
|
||||
|
||||
if (mockingBoardSpeechIsBusy())
|
||||
return false;
|
||||
|
||||
mockingBoardSpeechData = data;
|
||||
mockingBoardSpeechLen = dataLen + 1;
|
||||
mockingBoardSpeakPriv();
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
//
|
||||
// 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_CHANNLE_B 16
|
||||
#define NOISE_CHANNEL_C 32
|
||||
|
||||
#define ENABLE_CHANNEL(channels) (0x3f ^ (channels))
|
||||
|
||||
#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 void mockingBoardInit(tSlot slot, bool hasSpeechChip);
|
||||
extern void mockingBoardShutdown(void);
|
||||
|
||||
extern void mockingBoardPlaySound(tMockingBoardSpeaker speaker, tMockingSoundRegisters *registers);
|
||||
extern void mockingBoardStopSound(tMockingBoardSpeaker speaker);
|
||||
|
||||
extern bool mockingBoardSpeechIsBusy(void);
|
||||
extern bool mockingBoardSpeechIsPlaying(void);
|
||||
extern bool mockingBoardSpeak(uint8_t *data, uint16_t dataLen);
|
||||
|
||||
|
||||
#endif /* defined(__mocktest__mockingboard__) */
|
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// mockingboard_speech.h
|
||||
// mocktest
|
||||
//
|
||||
// Created by Jeremy Rand on 2016-10-17.
|
||||
// Copyright © 2016 Jeremy Rand. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef mockingboard_speech_h
|
||||
#define mockingboard_speech_h
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
extern uint8_t *mockingBoardSpeechData;
|
||||
extern uint16_t mockingBoardSpeechLen;
|
||||
extern uint8_t mockingBoardSpeechBusy;
|
||||
extern uint8_t mockingBoardSpeechPlaying;
|
||||
|
||||
extern void mockingBoardSpeechInit(uint8_t slot);
|
||||
extern void mockingBoardSpeechShutdown(void);
|
||||
extern void mockingBoardSpeakPriv(void);
|
||||
|
||||
|
||||
#endif /* mockingboard_speech_h */
|
|
@ -0,0 +1,265 @@
|
|||
;
|
||||
; speech.s
|
||||
; mocktest
|
||||
;
|
||||
; Created by Jeremy Rand on 2016-09-29.
|
||||
; Copyright © 2016 Jeremy Rand. All rights reserved.
|
||||
;
|
||||
|
||||
|
||||
.export _mockingBoardSpeechInit, _mockingBoardSpeechShutdown, _mockingBoardSpeakPriv
|
||||
.export _mockingBoardSpeechData, _mockingBoardSpeechLen
|
||||
.export _mockingBoardSpeechBusy, _mockingBoardSpeechPlaying
|
||||
.interruptor mock_irq
|
||||
|
||||
|
||||
TMPPTR := $FB ; Temporary pointer used in interrupt handler
|
||||
IRQL := $03FE ; Interrupt vector, low byte
|
||||
IRQH := $03FF ; Interrupt vector, high byte
|
||||
BASE := $40 ; First speech chip
|
||||
DURPHON := BASE ; Register 0 of speech chip
|
||||
INFLECT := BASE+$01 ; Register 1 of speech chip
|
||||
RATEINF := BASE+$02 ; Register 2 of speech chip
|
||||
CTTRAMP := BASE+$03 ; Register 3 of speech chip
|
||||
FILFREQ := BASE+$04 ; Register 4 of speech chip
|
||||
DDRB := $02
|
||||
DDRA := $03
|
||||
PCR := $8C ; Peripheral control register, 6522
|
||||
IFR := $8D ; Interrupt flag register, 6522
|
||||
IER := $8E
|
||||
|
||||
|
||||
.DATA
|
||||
_mockingBoardSpeechData: .byte $00, $00
|
||||
_mockingBoardSpeechLen: .byte $00, $00
|
||||
_outptr: .byte $00, $00
|
||||
_endptr: .byte $00, $00
|
||||
_mockingBoardSpeechBusy: .byte $00
|
||||
_mockingBoardSpeechPlaying: .byte $00
|
||||
|
||||
mock_irq: .byte $60
|
||||
.lobytes _mockInterrupt
|
||||
.hibytes _mockInterrupt
|
||||
|
||||
|
||||
.CODE
|
||||
|
||||
writeChip:
|
||||
sta $C000,X
|
||||
rts
|
||||
|
||||
readChip:
|
||||
lda $C000,X
|
||||
rts
|
||||
|
||||
|
||||
.proc _mockingBoardSpeechInit
|
||||
sei
|
||||
|
||||
; The accumulator has the slot number of the mockingboard.
|
||||
; Turn that into the address of the slot and set the address
|
||||
; in the read and write functions.
|
||||
and #$7
|
||||
ora #$c0
|
||||
sta writeChip+2
|
||||
sta readChip+2
|
||||
|
||||
; Write a jump instruction at mock_irq to turn on our handler
|
||||
lda #$4c
|
||||
sta mock_irq
|
||||
|
||||
cli
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
.proc _mockingBoardSpeechShutdown
|
||||
sei
|
||||
|
||||
; Write a RTS instruction at mock_irq to disable our handler
|
||||
lda #$60
|
||||
sta mock_irq
|
||||
|
||||
cli
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
.proc _mockingBoardSpeakPriv
|
||||
sei
|
||||
lda #$00
|
||||
ldx #DDRA
|
||||
jsr writeChip
|
||||
ldx #DDRB
|
||||
jsr writeChip
|
||||
|
||||
; Get the starting address of the data and store in the work pointer
|
||||
lda _mockingBoardSpeechData+1
|
||||
sta _outptr+1
|
||||
lda _mockingBoardSpeechData
|
||||
sta _outptr
|
||||
|
||||
; Calculate the end address from the start address and the length
|
||||
lda _mockingBoardSpeechLen+1
|
||||
clc
|
||||
adc _mockingBoardSpeechData+1
|
||||
sta _endptr+1
|
||||
lda _mockingBoardSpeechLen
|
||||
clc
|
||||
adc _mockingBoardSpeechData
|
||||
bcc @L2
|
||||
inc _endptr+1
|
||||
@L2:
|
||||
sta _endptr
|
||||
|
||||
; Set the busy flag
|
||||
lda #$FF
|
||||
sta _mockingBoardSpeechBusy
|
||||
|
||||
; Set peripheral control register to recognize the signal from the
|
||||
; speech chip.
|
||||
lda #$0C
|
||||
ldx #PCR
|
||||
jsr writeChip
|
||||
|
||||
; Raise control bit in register 3
|
||||
lda #$80
|
||||
ldx #CTTRAMP
|
||||
jsr writeChip
|
||||
|
||||
; Set transitioned inflection mode in register 0
|
||||
lda #$C0
|
||||
ldx #DURPHON
|
||||
jsr writeChip
|
||||
|
||||
; Lower control bit
|
||||
lda #$70
|
||||
ldx #CTTRAMP
|
||||
jsr writeChip
|
||||
|
||||
; Enable 6522 interrupts
|
||||
lda #$82
|
||||
ldx #IER
|
||||
jsr writeChip
|
||||
|
||||
cli
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
.proc _mockInterrupt
|
||||
; If we have a 6522 interrupt, jump to L4.
|
||||
ldx #IFR
|
||||
jsr readChip
|
||||
bmi @L4
|
||||
|
||||
; Otherwise clear the carry to indicate we didn't handle the interrupt
|
||||
; and return to the caller.
|
||||
clc
|
||||
rts
|
||||
|
||||
@L4:
|
||||
; Clear the interrupt flag
|
||||
lda #$02
|
||||
ldx #IFR
|
||||
jsr writeChip
|
||||
|
||||
; Check for end of data file. If not the end, jump to L1
|
||||
lda _outptr+1
|
||||
cmp _endptr+1
|
||||
bcc @L1
|
||||
bne @L5
|
||||
lda _outptr
|
||||
cmp _endptr
|
||||
bcc @L1
|
||||
|
||||
@L5:
|
||||
|
||||
; If at the end, turn everything off. Store a pause phoneme.
|
||||
lda #$00
|
||||
ldx #DURPHON
|
||||
jsr writeChip
|
||||
|
||||
; Zero amplitude
|
||||
lda #$70
|
||||
ldx #CTTRAMP
|
||||
jsr writeChip
|
||||
|
||||
; Clear busy and playing flags
|
||||
lda #$00
|
||||
sta _mockingBoardSpeechBusy
|
||||
sta _mockingBoardSpeechPlaying
|
||||
|
||||
; Clear interrupt enable in 6522
|
||||
lda #$02
|
||||
ldx #IER
|
||||
jsr writeChip
|
||||
lda #$FF
|
||||
ldx #DDRA
|
||||
jsr writeChip
|
||||
lda #$07
|
||||
ldx #DDRB
|
||||
jsr writeChip
|
||||
|
||||
@L2:
|
||||
; Set the carry flag to indicate we handled the interrupt and return to the caller.
|
||||
sec
|
||||
rts
|
||||
|
||||
@L1:
|
||||
|
||||
; Set the speach playing flag
|
||||
lda #$ff
|
||||
sta _mockingBoardSpeechPlaying
|
||||
|
||||
; Save the value of the tmp pointer on the stack
|
||||
lda TMPPTR
|
||||
pha
|
||||
lda TMPPTR+1
|
||||
pha
|
||||
|
||||
; Move the _outptr into the tmp pointer
|
||||
lda _outptr
|
||||
sta TMPPTR
|
||||
lda _outptr+1
|
||||
sta TMPPTR+1
|
||||
|
||||
; Init registers
|
||||
ldy #$00
|
||||
ldx #FILFREQ
|
||||
|
||||
@L6:
|
||||
; Get the next data
|
||||
lda (TMPPTR),Y
|
||||
|
||||
; Store in the speech chip
|
||||
jsr writeChip
|
||||
|
||||
; Next data
|
||||
inc TMPPTR
|
||||
bne @L3
|
||||
inc TMPPTR+1
|
||||
|
||||
@L3:
|
||||
; Go to next register
|
||||
dex
|
||||
|
||||
; If we are not done the last register, then loop back to L6
|
||||
cpx #BASE-1
|
||||
bne @L6
|
||||
|
||||
; We are done writing so move the tmp pointer back into _outptr
|
||||
lda TMPPTR
|
||||
sta _outptr
|
||||
lda TMPPTR+1
|
||||
sta _outptr+1
|
||||
|
||||
; Restore the tmp pointer from the stack
|
||||
pla
|
||||
sta TMPPTR+1
|
||||
pla
|
||||
sta TMPPTR
|
||||
|
||||
; Finish the interrupt handler
|
||||
jmp @L2
|
||||
.endproc
|
|
@ -0,0 +1,138 @@
|
|||
//
|
||||
// sound.c
|
||||
// a2bejwld
|
||||
//
|
||||
// Created by Jeremy Rand on 2016-12-18.
|
||||
// Copyright © 2016 Jeremy Rand. All rights reserved.
|
||||
//
|
||||
|
||||
#include "sound.h"
|
||||
#include "ui.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// Defines
|
||||
|
||||
#define CLEAR_GEM_SOUND_NORMAL 0
|
||||
#define CLEAR_GEM_SOUND_STAR 1
|
||||
#define CLEAR_GEM_SOUND_SPECIAL 2
|
||||
#define CLEAR_GEM_SOUND_EXPLODE 3
|
||||
#define NUM_CLEAR_GEM_SOUNDS 4
|
||||
|
||||
|
||||
// Globals
|
||||
|
||||
static uint8_t gSoundClearGem = 0;
|
||||
|
||||
static uint8_t gClearGemSoundFreq[NUM_CLEAR_GEM_SOUNDS][8] = {
|
||||
{ // CLEAR_GEM_SOUND_NORMAL
|
||||
30, 25, 20, 30, 30, 30, 30, 0 },
|
||||
{ // CLEAR_GEM_SOUND_STAR
|
||||
10, 9, 8, 7, 6, 5, 4, 0 },
|
||||
{ // CLEAR_GEM_SOUND_SPECIAL
|
||||
4, 6, 8, 10, 8, 6, 4, 0 },
|
||||
{ // CLEAR_GEM_SOUND_EXPLODE
|
||||
50, 60, 50, 60, 50, 60, 50, 0 }
|
||||
};
|
||||
|
||||
static uint8_t gClearGemSoundDuration[NUM_CLEAR_GEM_SOUNDS][8] = {
|
||||
{ // CLEAR_GEM_SOUND_NORMAL
|
||||
10, 15, 20, 10, 10, 10, 10, 0 },
|
||||
{ // CLEAR_GEM_SOUND_STAR
|
||||
30, 31, 32, 33, 34, 35, 36, 0 },
|
||||
{ // CLEAR_GEM_SOUND_SPECIAL
|
||||
36, 34, 32, 30, 32, 34, 36, 0 },
|
||||
{ // CLEAR_GEM_SOUND_EXPLODE
|
||||
8, 8, 8, 8, 8, 8, 8, 0 },
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// Implementation
|
||||
|
||||
|
||||
static void playSound(int8_t startFreq, int8_t duration)
|
||||
{
|
||||
int8_t freq;
|
||||
|
||||
while (duration > 0) {
|
||||
asm ("STA %w", 0xc030);
|
||||
freq = startFreq;
|
||||
while (freq > 0) {
|
||||
freq--;
|
||||
}
|
||||
duration--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void beginClearGemSound(void)
|
||||
{
|
||||
gSoundClearGem = (1 << CLEAR_GEM_SOUND_NORMAL);
|
||||
}
|
||||
|
||||
|
||||
void playSoundForExplodingGem(void)
|
||||
{
|
||||
gSoundClearGem |= (1 << CLEAR_GEM_SOUND_EXPLODE);
|
||||
}
|
||||
|
||||
|
||||
void playSoundForStarringGem(void)
|
||||
{
|
||||
gSoundClearGem |= (1 << CLEAR_GEM_SOUND_STAR);
|
||||
}
|
||||
|
||||
|
||||
void playSoundForSpecialGem(void)
|
||||
{
|
||||
gSoundClearGem |= (1 << CLEAR_GEM_SOUND_SPECIAL);
|
||||
}
|
||||
|
||||
|
||||
void playClearGemSound(uint8_t frame)
|
||||
{
|
||||
static uint8_t *clearGemSoundFreq;
|
||||
static uint8_t *clearGemSoundDuration;
|
||||
|
||||
if (!soundEnabled())
|
||||
return;
|
||||
|
||||
if (mockingBoardEnabled()) {
|
||||
// Do something here...
|
||||
} else {
|
||||
if (frame == 0) {
|
||||
uint8_t clearGemSound = CLEAR_GEM_SOUND_NORMAL;
|
||||
|
||||
if ((gSoundClearGem & (1 << CLEAR_GEM_SOUND_EXPLODE)) != 0) {
|
||||
clearGemSound = CLEAR_GEM_SOUND_EXPLODE;
|
||||
} else if ((gSoundClearGem & (1 << CLEAR_GEM_SOUND_SPECIAL)) != 0) {
|
||||
clearGemSound = CLEAR_GEM_SOUND_SPECIAL;
|
||||
} else if ((gSoundClearGem & (1 << CLEAR_GEM_SOUND_STAR)) != 0) {
|
||||
clearGemSound = CLEAR_GEM_SOUND_STAR;
|
||||
}
|
||||
|
||||
clearGemSoundFreq = &(gClearGemSoundFreq[clearGemSound][0]);
|
||||
clearGemSoundDuration = &(gClearGemSoundDuration[clearGemSound][0]);
|
||||
}
|
||||
|
||||
playSound(*clearGemSoundFreq, *clearGemSoundDuration);
|
||||
clearGemSoundFreq++;
|
||||
clearGemSoundDuration++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void playLandingSound(void)
|
||||
{
|
||||
if (!soundEnabled())
|
||||
return;
|
||||
|
||||
if (mockingBoardEnabled()) {
|
||||
// Do something here...
|
||||
} else {
|
||||
playSound(1, 1);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// sound.h
|
||||
// a2bejwld
|
||||
//
|
||||
// Created by Jeremy Rand on 2016-12-18.
|
||||
// Copyright © 2016 Jeremy Rand. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __a2bejwld__sound__
|
||||
#define __a2bejwld__sound__
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
extern void beginClearGemSound(void);
|
||||
extern void playSoundForExplodingGem(void);
|
||||
extern void playSoundForStarringGem(void);
|
||||
extern void playSoundForSpecialGem(void);
|
||||
extern void playClearGemSound(uint8_t frame);
|
||||
|
||||
extern void playLandingSound(void);
|
||||
|
||||
|
||||
#endif /* defined(__a2bejwld__sound__) */
|
|
@ -19,12 +19,13 @@
|
|||
#include "joystick.h"
|
||||
#include "machine.h"
|
||||
#include "mouseWrapper.h"
|
||||
#include "sound.h"
|
||||
|
||||
|
||||
// Defines
|
||||
|
||||
#define SAVE_OPTIONS_FILE "a2bejwld.opts"
|
||||
#define VERSION "v1.2"
|
||||
#define VERSION "v2.0"
|
||||
|
||||
|
||||
// Typedefs
|
||||
|
@ -103,6 +104,18 @@ static tGameOptions gGameOptions = {
|
|||
// Implementation
|
||||
|
||||
|
||||
bool soundEnabled(void)
|
||||
{
|
||||
return gGameOptions.enableSound;
|
||||
}
|
||||
|
||||
|
||||
bool mockingBoardEnabled(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void badThingHappened(void)
|
||||
{
|
||||
if (gGameOptions.enableSound)
|
||||
|
@ -110,24 +123,6 @@ void badThingHappened(void)
|
|||
}
|
||||
|
||||
|
||||
void playSound(int8_t startFreq, int8_t duration)
|
||||
{
|
||||
int8_t freq;
|
||||
|
||||
if (!gGameOptions.enableSound)
|
||||
return;
|
||||
|
||||
while (duration > 0) {
|
||||
asm ("STA %w", 0xc030);
|
||||
freq = startFreq;
|
||||
while (freq > 0) {
|
||||
freq--;
|
||||
}
|
||||
duration--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void showAndClearDblLoRes(void)
|
||||
{
|
||||
showDblLoRes();
|
||||
|
|
|
@ -10,18 +10,19 @@
|
|||
#define __a2bejwld__ui__
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
// API
|
||||
|
||||
extern void initUI(void);
|
||||
|
||||
extern bool soundEnabled(void);
|
||||
extern bool mockingBoardEnabled(void);
|
||||
|
||||
extern void printInstructions(void);
|
||||
|
||||
extern void playGame(void);
|
||||
|
||||
extern void playSound(int8_t startFreq, int8_t duration);
|
||||
|
||||
|
||||
#endif /* defined(__a2bejwld__ui__) */
|
||||
|
|
Loading…
Reference in New Issue