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 "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() {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue