This repository has been archived on 2023-07-11. You can view files and clone it, but cannot push or open issues or pull requests.
chocolate-doom-wii/opl/examples/droplay.c
2016-10-30 18:40:00 -04:00

211 lines
3.9 KiB
C

//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Demonstration program for OPL library to play back DRO
// format files.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL.h"
#include "opl.h"
#define HEADER_STRING "DBRAWOPL"
#define ADLIB_PORT 0x388
void WriteReg(unsigned int reg, unsigned int val)
{
int i;
// This was recorded from an OPL2, but we are probably playing
// back on an OPL3, so we need to enable the original OPL2
// channels. Doom does this already, but other games don't.
if ((reg & 0xf0) == OPL_REGS_FEEDBACK)
{
val |= 0x30;
}
OPL_WritePort(OPL_REGISTER_PORT, reg);
for (i=0; i<6; ++i)
{
OPL_ReadPort(OPL_REGISTER_PORT);
}
OPL_WritePort(OPL_DATA_PORT, val);
for (i=0; i<35; ++i)
{
OPL_ReadPort(OPL_REGISTER_PORT);
}
}
void ClearAllRegs(void)
{
int i;
for (i=0; i<=0xff; ++i)
{
WriteReg(i, 0x00);
}
}
void Init(void)
{
if (SDL_Init(SDL_INIT_TIMER) < 0)
{
fprintf(stderr, "Unable to initialise SDL timer\n");
exit(-1);
}
if (!OPL_Init(ADLIB_PORT))
{
fprintf(stderr, "Unable to initialise OPL layer\n");
exit(-1);
}
}
void Shutdown(void)
{
OPL_Shutdown();
}
struct timer_data
{
int running;
FILE *fstream;
};
void TimerCallback(void *data)
{
struct timer_data *timer_data = data;
int delay;
if (!timer_data->running)
{
return;
}
// Read data until we must make a delay.
for (;;)
{
int reg, val;
// End of file?
if (feof(timer_data->fstream))
{
timer_data->running = 0;
return;
}
reg = fgetc(timer_data->fstream);
val = fgetc(timer_data->fstream);
// Register value of 0 or 1 indicates a delay.
if (reg == 0x00)
{
delay = val;
break;
}
else if (reg == 0x01)
{
val |= (fgetc(timer_data->fstream) << 8);
delay = val;
break;
}
else
{
WriteReg(reg, val);
}
}
// Schedule the next timer callback.
OPL_SetCallback(delay * OPL_MS, TimerCallback, timer_data);
}
void PlayFile(char *filename)
{
struct timer_data timer_data;
int running;
char buf[8];
timer_data.fstream = fopen(filename, "rb");
if (timer_data.fstream == NULL)
{
fprintf(stderr, "Failed to open %s\n", filename);
exit(-1);
}
if (fread(buf, 1, 8, timer_data.fstream) < 8)
{
fprintf(stderr, "failed to read raw OPL header\n");
exit(-1);
}
if (strncmp(buf, HEADER_STRING, 8) != 0)
{
fprintf(stderr, "Raw OPL header not found\n");
exit(-1);
}
fseek(timer_data.fstream, 28, SEEK_SET);
timer_data.running = 1;
// Start callback loop sequence.
OPL_SetCallback(0, TimerCallback, &timer_data);
// Sleep until the playback finishes.
do
{
OPL_Lock();
running = timer_data.running;
OPL_Unlock();
SDL_Delay(100 * OPL_MS);
} while (running);
fclose(timer_data.fstream);
}
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("Usage: %s <filename>\n", argv[0]);
exit(-1);
}
Init();
PlayFile(argv[1]);
ClearAllRegs();
Shutdown();
return 0;
}