Skip to content

Minimal sound implementation take 2 #17

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

DEBUG ?= 0
MEMSIZE ?= 128
ENABLE_AUDIO ?= 1

SOURCES = $(wildcard src/*.c)

Expand Down Expand Up @@ -54,7 +55,7 @@ endif
# Basic support for changing screen res (with the MacPlusV3 ROM)
DISP_WIDTH ?= 512
DISP_HEIGHT ?= 342
CFLAGS_CFG = -DDISP_WIDTH=$(DISP_WIDTH) -DDISP_HEIGHT=$(DISP_HEIGHT)
CFLAGS_CFG = -DDISP_WIDTH=$(DISP_WIDTH) -DDISP_HEIGHT=$(DISP_HEIGHT) -DENABLE_AUDIO=$(ENABLE_AUDIO)

all: main

Expand Down
2 changes: 2 additions & 0 deletions include/machw.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ extern int overlay;
* But, that should never happen post-boot.
*/
#define CLAMP_RAM_ADDR(x) ((x) >= RAM_SIZE ? (x) % RAM_SIZE : (x))
/* Is the address (previously clamped with CLAMP_RAM_ADDR) the audio trap address? (last byte of audio data) */
#define IS_RAM_AUDIO_TRAP(x) (x == umac_get_audio_offset() + 2 * 369)

#define IS_VIA(x) ((ADR24(x) & 0xe80000) == 0xe80000)
#define IS_IWM(x) ((ADR24(x) >= 0xdfe1ff) && (ADR24(x) < (0xdfe1ff + 0x2000)))
Expand Down
7 changes: 7 additions & 0 deletions include/umac.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,11 @@ static inline unsigned int umac_get_fb_offset(void)
return RAM_SIZE - ((DISP_WIDTH * DISP_HEIGHT / 8) + 0x380);
}

#if ENABLE_AUDIO
#define umac_get_audio_offset() (RAM_SIZE - 768)

void umac_audio_trap();
void umac_audio_cfg(int volume, int sndres);
#endif

#endif
28 changes: 27 additions & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <errno.h>
#include <setjmp.h>

#include "umac.h"
#include "machw.h"
#include "m68k.h"
#include "via.h"
Expand Down Expand Up @@ -70,6 +71,9 @@ static unsigned int g_int_controller_highest_int = 0; /* Highest pending interr
uint8_t *_ram_base;
uint8_t *_rom_base;

#if ENABLE_AUDIO
static int umac_volume, umac_sndres;
#endif
int overlay = 1;
static uint64_t global_time_us = 0;
static int sim_done = 0;
Expand Down Expand Up @@ -155,6 +159,14 @@ static void via_ra_changed(uint8_t val)
update_overlay_layout();
}

#if ENABLE_AUDIO
uint8_t vol = val & 7;
if (vol != umac_volume) {
umac_volume = val & 7;
umac_audio_cfg(umac_volume, umac_sndres);
}
#endif

oldval = val;
}

Expand All @@ -166,7 +178,15 @@ static void via_rb_changed(uint8_t val)
// 4 = mouse4 (in, mouse X2)
// 3 = mouse7 (in, 0 = button pressed)
// [2:0] = RTC controls
#if ENABLE_AUDIO
uint8_t sndres = val >> 7;
if(sndres != umac_sndres) {
umac_sndres = sndres;
umac_audio_cfg(umac_volume, umac_sndres);
}
#else
(void)val;
#endif
}

static uint8_t via_ra_in(void)
Expand Down Expand Up @@ -437,7 +457,13 @@ unsigned int cpu_read_long_dasm(unsigned int address)
void FAST_FUNC(cpu_write_byte)(unsigned int address, unsigned int value)
{
if (IS_RAM(address)) {
RAM_WR8(CLAMP_RAM_ADDR(address), value);
address = CLAMP_RAM_ADDR(address);
RAM_WR8(address, value);
#if ENABLE_AUDIO
if(IS_RAM_AUDIO_TRAP(address)) {
umac_audio_trap();
}
#endif
return;
}

Expand Down
3 changes: 3 additions & 0 deletions src/rom.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ static void rom_patch_plusv3(uint8_t *rom_base)
* allowing the ROM checksum to fail (it returns failure, then
* we carry on). This avoids wild RAM addrs being accessed.
*/

/* Fix up the sound buffer as used by BootBeep */
ROM_WR32(0x292, RAM_SIZE - 768);
#endif

#if DISP_WIDTH != 512 || DISP_HEIGHT != 342
Expand Down
84 changes: 80 additions & 4 deletions src/unix_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
* SOFTWARE.
*/

#include <assert.h>
#include <stdio.h>
#include <fcntl.h>
#include <getopt.h>
Expand All @@ -35,6 +36,9 @@
#include <sys/time.h>
#include <string.h>
#include <unistd.h>
#if ENABLE_AUDIO
#include <stdatomic.h>
#endif
#include "SDL.h"

#include "rom.h"
Expand Down Expand Up @@ -78,6 +82,42 @@ static void copy_fb(uint32_t *fb_out, uint8_t *fb_in)
}
}

#if ENABLE_AUDIO
// audio_callback is called from a thread, so pending_v_retrace can't be a regular variable
atomic_int pending_v_retrace;
static int volscale;
uint8_t *audio_base;

int16_t audio[370];

void umac_audio_cfg(int umac_volume, int umac_sndres) {
volscale = umac_sndres ? 0 : 65536 * umac_volume / 7;
}

void umac_audio_trap() {
int32_t offset = 128;
uint16_t *audiodata = (uint16_t*)audio_base;
int scale = volscale;
if (!scale) {
memset(audio, 0, sizeof(audio));
return;
}
int16_t *stream = audio;
for(int i=0; i<370; i++) {
int32_t a = (*audiodata++ & 0xff) - offset;
a = (a * scale) >> 8;
*stream++ = a;
}
}

static void audio_callback(void *userdata, Uint8 *stream_in, int len_bytes) {
(void) userdata;
assert(len_bytes == sizeof(audio));
atomic_store(&pending_v_retrace, 1);
memcpy(stream_in, audio, sizeof(audio));
}
#endif

/**********************************************************************/

/* The emulator core expects to be given ROM and RAM pointers,
Expand Down Expand Up @@ -232,7 +272,11 @@ int main(int argc, char *argv[])
SDL_Renderer *renderer;
SDL_Texture *texture;

SDL_Init(SDL_INIT_VIDEO);
SDL_Init(SDL_INIT_VIDEO
#if ENABLE_AUDIO
| SDL_INIT_AUDIO
#endif
);
SDL_Window *window = SDL_CreateWindow("umac",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
Expand Down Expand Up @@ -264,18 +308,47 @@ int main(int argc, char *argv[])
return 1;
}

#if ENABLE_AUDIO
SDL_AudioSpec desired, obtained;

audio_base = (uint8_t*)ram_base + umac_get_audio_offset();

SDL_zero(desired);
desired.freq = 22256; // wat
desired.channels = 1;
desired.samples = 370;
desired.userdata = (uint8_t*)ram_base + umac_get_audio_offset();
desired.callback = audio_callback;
desired.format = AUDIO_S16;

SDL_AudioDeviceID audio_device = SDL_OpenAudioDevice(NULL, 0, &desired, &obtained, 0);
if (!audio_device) {
char buf[500];
SDL_GetErrorMsg(buf, sizeof(buf));
printf("SDL audio_deviceSDL_GetError() -> %s\n", buf);
return 1;
}
#endif

////////////////////////////////////////////////////////////////////////
// Emulator init

umac_init(ram_base, rom_base, discs);
umac_opt_disassemble(opt_disassemble);

#if ENABLE_AUDIO
// Default state is paused, this unpauses it
SDL_PauseAudioDevice(audio_device, 0);
#endif

////////////////////////////////////////////////////////////////////////
// Main loop

int done = 0;
int mouse_button = 0;
#if !ENABLE_AUDIO
uint64_t last_vsync = 0;
#endif
uint64_t last_1hz = 0;
do {
struct timeval tv_now;
Expand Down Expand Up @@ -321,11 +394,14 @@ int main(int argc, char *argv[])
uint64_t now_usec = (tv_now.tv_sec * 1000000) + tv_now.tv_usec;

/* Passage of time: */
if ((now_usec - last_vsync) >= 16667) {
#if ENABLE_AUDIO
int do_v_retrace = atomic_exchange(&pending_v_retrace, 0);
#else
int do_v_retrace = (now_usec - last_vsync) >= 16667;
#endif
if (do_v_retrace) {
umac_vsync_event();
last_vsync = now_usec;

/* Cheapo framerate limiting: */
copy_fb(framebuffer, ram_get_base() + umac_get_fb_offset());
SDL_UpdateTexture(texture, NULL, framebuffer,
DISP_WIDTH * sizeof (Uint32));
Expand Down