Progress on channel assignment in DRO output.
This commit is contained in:
parent
a16025e39c
commit
454fbdfde5
6 changed files with 105 additions and 51 deletions
|
@ -1,11 +1,14 @@
|
|||
#include "DROMultiplexer.h"
|
||||
|
||||
#include "JuceHeader.h"
|
||||
#include <Windows.h>
|
||||
|
||||
// Used by the first recording instance to claim master status
|
||||
// TODO: develop the logic for recording data from other (non-master) plugins
|
||||
DROMultiplexer* DROMultiplexer::master = NULL;
|
||||
|
||||
// Mutex between plugin instances
|
||||
CriticalSection DROMultiplexer::lock;
|
||||
|
||||
static Bit8u dro_header[] = {
|
||||
'D', 'B', 'R', 'A', /* 0x00, Bit32u ID */
|
||||
'W', 'O', 'P', 'L', /* 0x04, Bit32u ID */
|
||||
|
@ -68,32 +71,51 @@ INLINE void host_writed(Bit8u *off, Bit32u val) {
|
|||
off[3] = (Bit8u)(val >> 24);
|
||||
};
|
||||
|
||||
HANDLE conout;
|
||||
DROMultiplexer::DROMultiplexer()
|
||||
{
|
||||
for (int i = 0; i < MELODIC_CHANNELS; ++i) {
|
||||
for (int i = 0; i < MELODIC_CHANNELS; i++) {
|
||||
channels[i].opl = NULL;
|
||||
channels[i].ch = -1;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
AllocConsole();
|
||||
conout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
#endif
|
||||
}
|
||||
|
||||
DROMultiplexer::~DROMultiplexer()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
FreeConsole();
|
||||
#endif
|
||||
}
|
||||
|
||||
DROMultiplexer* DROMultiplexer::GetMaster() {
|
||||
return DROMultiplexer::master;
|
||||
}
|
||||
|
||||
void DROMultiplexer::TwoOpMelodicNoteOn(Hiopl* opl, int ch) {
|
||||
void DROMultiplexer::TwoOpMelodicNoteOn(Hiopl* opl, int inCh) {
|
||||
const ScopedLock sl(lock);
|
||||
|
||||
for (int i = 1; i <= Hiopl::CHANNELS; i++) {
|
||||
char s[2];
|
||||
s[0] = opl->GetState(i);
|
||||
s[1] = '\0';
|
||||
_DebugOut(s);
|
||||
}
|
||||
_DebugOut(" ");
|
||||
|
||||
// find a free channel and mark it as used
|
||||
int outCh = _FindFreeChannel();
|
||||
channels[outCh].opl = opl;
|
||||
channels[outCh].ch = ch;
|
||||
channelMap[channels[outCh]] = outCh;
|
||||
char addr[16];
|
||||
int outCh = _FindFreeChannel(opl, inCh);
|
||||
_DebugOut(" <- ");
|
||||
_DebugOut(itoa((int)opl, addr, 16));
|
||||
_DebugOut("\n");
|
||||
|
||||
// read all instrument settings and write them all to the file
|
||||
int op1Off = opl->_GetOffset(ch, 1);
|
||||
int op2Off = opl->_GetOffset(ch, 2);
|
||||
int op1Off = opl->_GetOffset(inCh, 1);
|
||||
int op2Off = opl->_GetOffset(inCh, 2);
|
||||
Bit32u inAddr;
|
||||
Bit32u outAddr;
|
||||
// waveform select
|
||||
|
@ -115,7 +137,7 @@ void DROMultiplexer::TwoOpMelodicNoteOn(Hiopl* opl, int ch) {
|
|||
}
|
||||
|
||||
// channel wide settings
|
||||
int chInOff = opl->_GetOffset(ch);
|
||||
int chInOff = opl->_GetOffset(inCh);
|
||||
inAddr = 0xc0 + chInOff;
|
||||
outAddr = 0xc0 + CHANNEL_OFFSETS[outCh];
|
||||
_CaptureRegWrite(outAddr, 0x30 | opl->_ReadReg(inAddr));
|
||||
|
@ -127,10 +149,11 @@ void DROMultiplexer::TwoOpMelodicNoteOn(Hiopl* opl, int ch) {
|
|||
inAddr = 0xb0 + chInOff;
|
||||
outAddr = 0xb0 + CHANNEL_OFFSETS[outCh];
|
||||
_CaptureRegWrite(outAddr, opl->_ReadReg(inAddr));
|
||||
|
||||
}
|
||||
|
||||
void DROMultiplexer::TwoOpMelodicNoteOff(Hiopl* opl, int ch) {
|
||||
const ScopedLock sl(lock);
|
||||
|
||||
int chOff = opl->_GetOffset(ch);
|
||||
OplCh_t key;
|
||||
key.opl = opl;
|
||||
|
@ -143,20 +166,33 @@ void DROMultiplexer::TwoOpMelodicNoteOff(Hiopl* opl, int ch) {
|
|||
_CaptureRegWriteWithDelay(outAddr, opl->_ReadReg(inAddr));
|
||||
}
|
||||
|
||||
int DROMultiplexer::_FindFreeChannel() {
|
||||
void DROMultiplexer::_DebugOut(char* str) {
|
||||
#ifdef _DEBUG
|
||||
DWORD count;
|
||||
count = strlen(str);
|
||||
WriteConsole(conout, str, count, &count, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
int DROMultiplexer::_FindFreeChannel(Hiopl* opl, int inCh) {
|
||||
int i = 0;
|
||||
while (i < MELODIC_CHANNELS) {
|
||||
Hiopl* opl = channels[i].opl;
|
||||
if (NULL == opl || !opl->IsActive(channels[i].ch)) {
|
||||
if (NULL == channels[i].opl || !channels[i].opl->IsActive(channels[i].ch)) {
|
||||
channels[i].opl = opl;
|
||||
channels[i].ch = inCh;
|
||||
channelMap[channels[i]] = i;
|
||||
char n[8];
|
||||
_DebugOut(itoa(i, n, 10));
|
||||
return i;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
// TODO: handle the fact that there are no free channels :(
|
||||
_DebugOut("Could not find free channel!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DROMultiplexer::PercussionHit(Hiopl* opl) {
|
||||
const ScopedLock sl(lock);
|
||||
|
||||
}
|
||||
|
||||
|
@ -165,38 +201,42 @@ void DROMultiplexer::InitCaptureVariables() {
|
|||
captureLengthBytes = 0;
|
||||
lastWrite = -1;
|
||||
captureStart = -1;
|
||||
// channelMap.clear();
|
||||
}
|
||||
|
||||
void DROMultiplexer::StartCapture(const char* filepath, Hiopl *opl) {
|
||||
DROMultiplexer::master = this;
|
||||
lastWrite = -1;
|
||||
captureLengthBytes = 0;
|
||||
captureStart = Time::currentTimeMillis();
|
||||
bool DROMultiplexer::StartCapture(const char* filepath, Hiopl *opl) {
|
||||
captureHandle = fopen(filepath, "wb");
|
||||
fwrite(dro_header, 1, sizeof(dro_header), captureHandle);
|
||||
for (int i = 0; i <= 0xff; i++) {
|
||||
_CaptureRegWrite(i, 0);
|
||||
}
|
||||
_CaptureOpl3Enable();
|
||||
for (Bit8u i = 0x20; i <= 0x35; i++) {
|
||||
_CaptureRegWrite(i, opl->_ReadReg(i));
|
||||
}
|
||||
for (Bit8u i = 0x40; i <= 0x55; i++) {
|
||||
_CaptureRegWrite(i, opl->_ReadReg(i));
|
||||
}
|
||||
for (Bit8u i = 0x60; i <= 0x75; i++) {
|
||||
_CaptureRegWrite(i, opl->_ReadReg(i));
|
||||
}
|
||||
for (Bit8u i = 0x80; i <= 0x95; i++) {
|
||||
_CaptureRegWrite(i, opl->_ReadReg(i));
|
||||
}
|
||||
_CaptureRegWrite(0xbd, opl->_ReadReg(0xbd));
|
||||
for (Bit8u i = 0xc0; i <= 0xc8; i++) {
|
||||
_CaptureRegWrite(i, opl->_ReadReg(i) | 0x30); // enable L + R channels
|
||||
}
|
||||
for (Bit8u i = 0xe0; i <= 0xf5; i++) {
|
||||
_CaptureRegWrite(i, opl->_ReadReg(i));
|
||||
if (captureHandle) {
|
||||
DROMultiplexer::master = this;
|
||||
lastWrite = -1;
|
||||
captureLengthBytes = 0;
|
||||
captureStart = Time::currentTimeMillis();
|
||||
fwrite(dro_header, 1, sizeof(dro_header), captureHandle);
|
||||
for (int i = 0; i <= 0xff; i++) {
|
||||
_CaptureRegWrite(i, 0);
|
||||
}
|
||||
_CaptureOpl3Enable();
|
||||
for (Bit8u i = 0x20; i <= 0x35; i++) {
|
||||
_CaptureRegWrite(i, opl->_ReadReg(i));
|
||||
}
|
||||
for (Bit8u i = 0x40; i <= 0x55; i++) {
|
||||
_CaptureRegWrite(i, opl->_ReadReg(i));
|
||||
}
|
||||
for (Bit8u i = 0x60; i <= 0x75; i++) {
|
||||
_CaptureRegWrite(i, opl->_ReadReg(i));
|
||||
}
|
||||
for (Bit8u i = 0x80; i <= 0x95; i++) {
|
||||
_CaptureRegWrite(i, opl->_ReadReg(i));
|
||||
}
|
||||
_CaptureRegWrite(0xbd, opl->_ReadReg(0xbd));
|
||||
for (Bit8u i = 0xc0; i <= 0xc8; i++) {
|
||||
_CaptureRegWrite(i, opl->_ReadReg(i) | 0x30); // enable L + R channels
|
||||
}
|
||||
for (Bit8u i = 0xe0; i <= 0xf5; i++) {
|
||||
_CaptureRegWrite(i, opl->_ReadReg(i));
|
||||
}
|
||||
}
|
||||
return (NULL != captureHandle);
|
||||
}
|
||||
|
||||
void DROMultiplexer::StopCapture() {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include <map>
|
||||
#include "hiopl.h"
|
||||
#include "../JuceLibraryCode/JuceHeader.h"
|
||||
|
||||
class DROMultiplexer
|
||||
{
|
||||
|
@ -17,7 +18,7 @@ public:
|
|||
void InitCaptureVariables();
|
||||
bool IsAnInstanceRecording();
|
||||
bool IsAnotherInstanceRecording();
|
||||
void StartCapture(const char* filepath, Hiopl* opl);
|
||||
bool StartCapture(const char* filepath, Hiopl* opl);
|
||||
void StopCapture();
|
||||
static DROMultiplexer* GetMaster();
|
||||
|
||||
|
@ -26,13 +27,15 @@ private:
|
|||
void _CaptureRegWriteWithDelay(Bit32u reg, Bit8u value);
|
||||
void _CaptureRegWrite(Bit32u reg, Bit8u value);
|
||||
void _CaptureOpl3Enable();
|
||||
int _FindFreeChannel();
|
||||
int _FindFreeChannel(Hiopl* opl, int inCh);
|
||||
void _DebugOut(char* str);
|
||||
static DROMultiplexer* master;
|
||||
|
||||
FILE* captureHandle;
|
||||
Bit64s captureStart;
|
||||
Bit64s lastWrite;
|
||||
Bit32u captureLengthBytes;
|
||||
static CriticalSection lock;
|
||||
|
||||
typedef struct oplch {
|
||||
Hiopl* opl;
|
||||
|
|
|
@ -152,7 +152,9 @@ bool JuceOplvstiAudioProcessor::isAnyInstanceRecording() {
|
|||
|
||||
void JuceOplvstiAudioProcessor::startRecording(File *outputFile) {
|
||||
recordingFile = outputFile;
|
||||
dro->StartCapture(outputFile->getFullPathName().toUTF8(), Opl);
|
||||
if (!dro->StartCapture(outputFile->getFullPathName().toUTF8(), Opl)) {
|
||||
juce::AlertWindow::showMessageBoxAsync(juce::AlertWindow::InfoIcon, "Could not open specified file for writing!", "OK");
|
||||
}
|
||||
}
|
||||
|
||||
void JuceOplvstiAudioProcessor::stopRecording() {
|
||||
|
@ -447,8 +449,8 @@ JuceOplvstiAudioProcessor::~JuceOplvstiAudioProcessor()
|
|||
{
|
||||
for (unsigned int i=0; i < params.size(); ++i)
|
||||
delete params[i];
|
||||
//delete Opl;
|
||||
//delete dro;
|
||||
delete Opl;
|
||||
delete dro;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
@ -529,9 +529,6 @@ void Operator::WriteE0( const Chip* chip, Bit8u val ) {
|
|||
INLINE void Operator::SetState( Bit8u s ) {
|
||||
state = s;
|
||||
volHandler = VolumeHandlerTable[ s ];
|
||||
if (OFF == s) {
|
||||
// TODO: callback
|
||||
}
|
||||
}
|
||||
|
||||
INLINE bool Operator::Silent() const {
|
||||
|
|
|
@ -190,6 +190,17 @@ void Hiopl::KeyOff(int ch) {
|
|||
_ClearRegBits(0xb0+offset, 0x20);
|
||||
}
|
||||
|
||||
static const char STATE[] = {
|
||||
'-',
|
||||
'R',
|
||||
'S',
|
||||
'D',
|
||||
'A',
|
||||
};
|
||||
char Hiopl::GetState(int ch) {
|
||||
return STATE[adlib->chip.chan[ch - 1].op[1].state];
|
||||
}
|
||||
|
||||
bool Hiopl::IsActive(int ch) {
|
||||
// check carrier envelope state
|
||||
return DBOPL::Operator::State::OFF != adlib->chip.chan[ch - 1].op[1].state;
|
||||
|
|
|
@ -68,6 +68,7 @@ class Hiopl {
|
|||
void KeyOff(int ch);
|
||||
// Return false if no note is active on the channel (ie release is complete)
|
||||
bool IsActive(int ch);
|
||||
char GetState(int ch);
|
||||
void SetFrequency(int ch, float frqHz, bool keyOn=false);
|
||||
void _WriteReg(Bit32u reg, Bit8u value, Bit8u mask=0x0);
|
||||
void _ClearRegBits(Bit32u reg, Bit8u mask);
|
||||
|
|
Loading…
Reference in a new issue