2
0
Fork 0

Progress on channel assignment in DRO output.

This commit is contained in:
Bruce Sutherland 2015-01-09 14:20:19 +09:00
parent a16025e39c
commit 454fbdfde5
6 changed files with 105 additions and 51 deletions

View file

@ -1,11 +1,14 @@
#include "DROMultiplexer.h" #include "DROMultiplexer.h"
#include "JuceHeader.h" #include "JuceHeader.h"
#include <Windows.h>
// Used by the first recording instance to claim master status // 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; DROMultiplexer* DROMultiplexer::master = NULL;
// Mutex between plugin instances
CriticalSection DROMultiplexer::lock;
static Bit8u dro_header[] = { static Bit8u dro_header[] = {
'D', 'B', 'R', 'A', /* 0x00, Bit32u ID */ 'D', 'B', 'R', 'A', /* 0x00, Bit32u ID */
'W', 'O', 'P', 'L', /* 0x04, 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); off[3] = (Bit8u)(val >> 24);
}; };
HANDLE conout;
DROMultiplexer::DROMultiplexer() DROMultiplexer::DROMultiplexer()
{ {
for (int i = 0; i < MELODIC_CHANNELS; ++i) { for (int i = 0; i < MELODIC_CHANNELS; i++) {
channels[i].opl = NULL; channels[i].opl = NULL;
channels[i].ch = -1; channels[i].ch = -1;
} }
#ifdef _DEBUG
AllocConsole();
conout = GetStdHandle(STD_OUTPUT_HANDLE);
#endif
} }
DROMultiplexer::~DROMultiplexer() DROMultiplexer::~DROMultiplexer()
{ {
#ifdef _DEBUG
FreeConsole();
#endif
} }
DROMultiplexer* DROMultiplexer::GetMaster() { DROMultiplexer* DROMultiplexer::GetMaster() {
return DROMultiplexer::master; 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 // find a free channel and mark it as used
int outCh = _FindFreeChannel(); char addr[16];
channels[outCh].opl = opl; int outCh = _FindFreeChannel(opl, inCh);
channels[outCh].ch = ch; _DebugOut(" <- ");
channelMap[channels[outCh]] = outCh; _DebugOut(itoa((int)opl, addr, 16));
_DebugOut("\n");
// read all instrument settings and write them all to the file // read all instrument settings and write them all to the file
int op1Off = opl->_GetOffset(ch, 1); int op1Off = opl->_GetOffset(inCh, 1);
int op2Off = opl->_GetOffset(ch, 2); int op2Off = opl->_GetOffset(inCh, 2);
Bit32u inAddr; Bit32u inAddr;
Bit32u outAddr; Bit32u outAddr;
// waveform select // waveform select
@ -115,7 +137,7 @@ void DROMultiplexer::TwoOpMelodicNoteOn(Hiopl* opl, int ch) {
} }
// channel wide settings // channel wide settings
int chInOff = opl->_GetOffset(ch); int chInOff = opl->_GetOffset(inCh);
inAddr = 0xc0 + chInOff; inAddr = 0xc0 + chInOff;
outAddr = 0xc0 + CHANNEL_OFFSETS[outCh]; outAddr = 0xc0 + CHANNEL_OFFSETS[outCh];
_CaptureRegWrite(outAddr, 0x30 | opl->_ReadReg(inAddr)); _CaptureRegWrite(outAddr, 0x30 | opl->_ReadReg(inAddr));
@ -127,10 +149,11 @@ void DROMultiplexer::TwoOpMelodicNoteOn(Hiopl* opl, int ch) {
inAddr = 0xb0 + chInOff; inAddr = 0xb0 + chInOff;
outAddr = 0xb0 + CHANNEL_OFFSETS[outCh]; outAddr = 0xb0 + CHANNEL_OFFSETS[outCh];
_CaptureRegWrite(outAddr, opl->_ReadReg(inAddr)); _CaptureRegWrite(outAddr, opl->_ReadReg(inAddr));
} }
void DROMultiplexer::TwoOpMelodicNoteOff(Hiopl* opl, int ch) { void DROMultiplexer::TwoOpMelodicNoteOff(Hiopl* opl, int ch) {
const ScopedLock sl(lock);
int chOff = opl->_GetOffset(ch); int chOff = opl->_GetOffset(ch);
OplCh_t key; OplCh_t key;
key.opl = opl; key.opl = opl;
@ -143,20 +166,33 @@ void DROMultiplexer::TwoOpMelodicNoteOff(Hiopl* opl, int ch) {
_CaptureRegWriteWithDelay(outAddr, opl->_ReadReg(inAddr)); _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; int i = 0;
while (i < MELODIC_CHANNELS) { while (i < MELODIC_CHANNELS) {
Hiopl* opl = channels[i].opl; if (NULL == channels[i].opl || !channels[i].opl->IsActive(channels[i].ch)) {
if (NULL == opl || !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; return i;
} }
i += 1; i += 1;
} }
// TODO: handle the fact that there are no free channels :( _DebugOut("Could not find free channel!");
return 0; return 0;
} }
void DROMultiplexer::PercussionHit(Hiopl* opl) { void DROMultiplexer::PercussionHit(Hiopl* opl) {
const ScopedLock sl(lock);
} }
@ -165,14 +201,16 @@ void DROMultiplexer::InitCaptureVariables() {
captureLengthBytes = 0; captureLengthBytes = 0;
lastWrite = -1; lastWrite = -1;
captureStart = -1; captureStart = -1;
// channelMap.clear();
} }
void DROMultiplexer::StartCapture(const char* filepath, Hiopl *opl) { bool DROMultiplexer::StartCapture(const char* filepath, Hiopl *opl) {
captureHandle = fopen(filepath, "wb");
if (captureHandle) {
DROMultiplexer::master = this; DROMultiplexer::master = this;
lastWrite = -1; lastWrite = -1;
captureLengthBytes = 0; captureLengthBytes = 0;
captureStart = Time::currentTimeMillis(); captureStart = Time::currentTimeMillis();
captureHandle = fopen(filepath, "wb");
fwrite(dro_header, 1, sizeof(dro_header), captureHandle); fwrite(dro_header, 1, sizeof(dro_header), captureHandle);
for (int i = 0; i <= 0xff; i++) { for (int i = 0; i <= 0xff; i++) {
_CaptureRegWrite(i, 0); _CaptureRegWrite(i, 0);
@ -197,6 +235,8 @@ void DROMultiplexer::StartCapture(const char* filepath, Hiopl *opl) {
for (Bit8u i = 0xe0; i <= 0xf5; i++) { for (Bit8u i = 0xe0; i <= 0xf5; i++) {
_CaptureRegWrite(i, opl->_ReadReg(i)); _CaptureRegWrite(i, opl->_ReadReg(i));
} }
}
return (NULL != captureHandle);
} }
void DROMultiplexer::StopCapture() { void DROMultiplexer::StopCapture() {

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <map> #include <map>
#include "hiopl.h" #include "hiopl.h"
#include "../JuceLibraryCode/JuceHeader.h"
class DROMultiplexer class DROMultiplexer
{ {
@ -17,7 +18,7 @@ public:
void InitCaptureVariables(); void InitCaptureVariables();
bool IsAnInstanceRecording(); bool IsAnInstanceRecording();
bool IsAnotherInstanceRecording(); bool IsAnotherInstanceRecording();
void StartCapture(const char* filepath, Hiopl* opl); bool StartCapture(const char* filepath, Hiopl* opl);
void StopCapture(); void StopCapture();
static DROMultiplexer* GetMaster(); static DROMultiplexer* GetMaster();
@ -26,13 +27,15 @@ private:
void _CaptureRegWriteWithDelay(Bit32u reg, Bit8u value); void _CaptureRegWriteWithDelay(Bit32u reg, Bit8u value);
void _CaptureRegWrite(Bit32u reg, Bit8u value); void _CaptureRegWrite(Bit32u reg, Bit8u value);
void _CaptureOpl3Enable(); void _CaptureOpl3Enable();
int _FindFreeChannel(); int _FindFreeChannel(Hiopl* opl, int inCh);
void _DebugOut(char* str);
static DROMultiplexer* master; static DROMultiplexer* master;
FILE* captureHandle; FILE* captureHandle;
Bit64s captureStart; Bit64s captureStart;
Bit64s lastWrite; Bit64s lastWrite;
Bit32u captureLengthBytes; Bit32u captureLengthBytes;
static CriticalSection lock;
typedef struct oplch { typedef struct oplch {
Hiopl* opl; Hiopl* opl;

View file

@ -152,7 +152,9 @@ bool JuceOplvstiAudioProcessor::isAnyInstanceRecording() {
void JuceOplvstiAudioProcessor::startRecording(File *outputFile) { void JuceOplvstiAudioProcessor::startRecording(File *outputFile) {
recordingFile = 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() { void JuceOplvstiAudioProcessor::stopRecording() {
@ -447,8 +449,8 @@ JuceOplvstiAudioProcessor::~JuceOplvstiAudioProcessor()
{ {
for (unsigned int i=0; i < params.size(); ++i) for (unsigned int i=0; i < params.size(); ++i)
delete params[i]; delete params[i];
//delete Opl; delete Opl;
//delete dro; delete dro;
} }
//============================================================================== //==============================================================================

View file

@ -529,9 +529,6 @@ void Operator::WriteE0( const Chip* chip, Bit8u val ) {
INLINE void Operator::SetState( Bit8u s ) { INLINE void Operator::SetState( Bit8u s ) {
state = s; state = s;
volHandler = VolumeHandlerTable[ s ]; volHandler = VolumeHandlerTable[ s ];
if (OFF == s) {
// TODO: callback
}
} }
INLINE bool Operator::Silent() const { INLINE bool Operator::Silent() const {

View file

@ -190,6 +190,17 @@ void Hiopl::KeyOff(int ch) {
_ClearRegBits(0xb0+offset, 0x20); _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) { bool Hiopl::IsActive(int ch) {
// check carrier envelope state // check carrier envelope state
return DBOPL::Operator::State::OFF != adlib->chip.chan[ch - 1].op[1].state; return DBOPL::Operator::State::OFF != adlib->chip.chan[ch - 1].op[1].state;

View file

@ -68,6 +68,7 @@ class Hiopl {
void KeyOff(int ch); void KeyOff(int ch);
// Return false if no note is active on the channel (ie release is complete) // Return false if no note is active on the channel (ie release is complete)
bool IsActive(int ch); bool IsActive(int ch);
char GetState(int ch);
void SetFrequency(int ch, float frqHz, bool keyOn=false); void SetFrequency(int ch, float frqHz, bool keyOn=false);
void _WriteReg(Bit32u reg, Bit8u value, Bit8u mask=0x0); void _WriteReg(Bit32u reg, Bit8u value, Bit8u mask=0x0);
void _ClearRegBits(Bit32u reg, Bit8u mask); void _ClearRegBits(Bit32u reg, Bit8u mask);