1199 lines
40 KiB
C++
1199 lines
40 KiB
C++
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <fstream>
|
|
#include <math.h>
|
|
#include <algorithm>
|
|
#include <atomic>
|
|
|
|
#include "memory.h"
|
|
#include "loader.h"
|
|
#include "cpu.h"
|
|
#include "audio.h"
|
|
#include "midi.h"
|
|
#include "timing.h"
|
|
#include "editor.h"
|
|
#include "graphics.h"
|
|
#include "menu.h"
|
|
#include "dialog.h"
|
|
#include "terminal.h"
|
|
#include "expression.h"
|
|
#include "inih/INIReader.h"
|
|
|
|
#include <SDL.h>
|
|
|
|
|
|
#define AUDIO_SAMPLES (SCAN_LINES)
|
|
#define AUDIO_BUFFER_SIZE (SCAN_LINES*4)
|
|
#define AUDIO_FREQUENCY (int(SCAN_LINES*59.98))
|
|
|
|
#define XOUT_MASK 0xFC
|
|
|
|
#define MAX_WAVE_X 64
|
|
#define MAX_WAVE_Y 64
|
|
#define BORDER_X1 15
|
|
#define BORDER_X2 144
|
|
#define BORDER_Y1 45
|
|
#define BORDER_Y2 (BORDER_Y1 + MAX_WAVE_Y + 1)
|
|
#define BOTTOM_ROW (BORDER_Y2 + 2)
|
|
|
|
#define MAX_COMMAND_CHARS 79
|
|
#define MIDI_TEXT_ROW 164
|
|
#define WAVE_TEXT_ROW (SCREEN_HEIGHT - (FONT_HEIGHT+4))
|
|
|
|
|
|
namespace Audio
|
|
{
|
|
bool _realTimeAudio = true;
|
|
|
|
SDL_AudioDeviceID _audioDevice = 1;
|
|
|
|
std::atomic<int64_t> _audioInIndex(AUDIO_SAMPLES*2);
|
|
std::atomic<int64_t> _audioOutIndex(0);
|
|
uint16_t _audioSamples[AUDIO_BUFFER_SIZE] = {0};
|
|
|
|
uint8_t _waveTables[256];
|
|
|
|
INIReader _configIniReader;
|
|
|
|
|
|
bool getRealTimeAudio(void) {return _realTimeAudio;}
|
|
|
|
bool getKeyAsString(const std::string& sectionString, const std::string& iniKey, const std::string& defaultKey, std::string& result)
|
|
{
|
|
result = _configIniReader.Get(sectionString, iniKey, defaultKey);
|
|
if(result == defaultKey) return false;
|
|
Expression::strToUpper(result);
|
|
return true;
|
|
}
|
|
|
|
void sdl2AudioCallback(void* userData, unsigned char *stream, int length)
|
|
{
|
|
UNREFERENCED_PARAM(userData);
|
|
|
|
int16_t *sdl2Stream = (int16_t *)stream;
|
|
|
|
for(int i=0; i<length/2; i++)
|
|
{
|
|
if(_audioOutIndex % AUDIO_BUFFER_SIZE == _audioInIndex % AUDIO_BUFFER_SIZE)
|
|
{
|
|
sdl2Stream[i] = _audioSamples[(_audioOutIndex-1) % AUDIO_BUFFER_SIZE];
|
|
}
|
|
else
|
|
{
|
|
sdl2Stream[i] = _audioSamples[_audioOutIndex++ % AUDIO_BUFFER_SIZE];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void initialise(void)
|
|
{
|
|
// Loader config
|
|
INIReader iniReader(Loader::getExePath() + "/" + AUDIO_CONFIG_INI);
|
|
_configIniReader = iniReader;
|
|
if(_configIniReader.ParseError() == 0)
|
|
{
|
|
// Parse Loader Keys
|
|
enum Section {Audio};
|
|
std::map<std::string, Section> section;
|
|
section["Audio"] = Audio;
|
|
for(auto sectionString : _configIniReader.Sections())
|
|
{
|
|
if(section.find(sectionString) == section.end())
|
|
{
|
|
fprintf(stderr, "Audio::initialise() : INI file '%s' has bad Sections : reverting to default values.\n", AUDIO_CONFIG_INI);
|
|
break;
|
|
}
|
|
|
|
std::string result;
|
|
switch(section[sectionString])
|
|
{
|
|
case Audio:
|
|
{
|
|
getKeyAsString(sectionString, "RealTimeAudio", "1", result);
|
|
_realTimeAudio = strtol(result.c_str(), nullptr, 10);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Audio::initialise() : couldn't find audio configuration INI file '%s' : reverting to default values.\n", AUDIO_CONFIG_INI);
|
|
}
|
|
|
|
SDL_AudioSpec audSpec;
|
|
SDL_zero(audSpec);
|
|
audSpec.freq = AUDIO_FREQUENCY;
|
|
audSpec.format = AUDIO_S16;
|
|
audSpec.channels = 1;
|
|
audSpec.callback = sdl2AudioCallback;
|
|
audSpec.samples = AUDIO_SAMPLES;
|
|
|
|
if(SDL_OpenAudio(&audSpec, NULL) < 0)
|
|
{
|
|
Cpu::shutdown();
|
|
fprintf(stderr, "Audio::initialise() : failed to initialise SDL audio\n");
|
|
_EXIT_(EXIT_FAILURE);
|
|
}
|
|
|
|
initialiseChannels();
|
|
|
|
SDL_PauseAudio(0);
|
|
|
|
initialiseEditor();
|
|
}
|
|
|
|
void saveWaveTables(void)
|
|
{
|
|
for(uint16_t i=0; i<256; i++) _waveTables[i] = Cpu::getRAM(0x0700 + i);
|
|
}
|
|
|
|
void restoreWaveTables(void)
|
|
{
|
|
for(uint16_t i=0; i<256; i++) Cpu::setRAM(0x0700 + i, _waveTables[i]);
|
|
}
|
|
|
|
void restoreWaveTable(uint16_t waveTable)
|
|
{
|
|
// Interlaced wavetables
|
|
for(uint16_t i=waveTable & 3; i<256; i+=4) Cpu::setRAM(0x0700 + i, _waveTables[i]);
|
|
}
|
|
|
|
void initialiseChannels(void)
|
|
{
|
|
// TODO: put this somewhere more appropriate
|
|
Cpu::setRAM(46, 0); // reset LED sequencer for ROMv2 and higher
|
|
|
|
// Reset channels
|
|
for(uint16_t i=0; i<GIGA_NUM_CHANNELS; i++)
|
|
{
|
|
Cpu::setRAM(GIGA_CH0_WAV_A + i*GIGA_CHANNEL_OFFSET, 0x00); // ADD modulation, (volume)
|
|
Cpu::setRAM(GIGA_CH0_WAV_X + i*GIGA_CHANNEL_OFFSET, 0x02); // waveform index and XOR index modulation, (noise)
|
|
Cpu::setRAM(GIGA_CH0_KEY_L + i*GIGA_CHANNEL_OFFSET, 0x00); // low frequency look up from ROM
|
|
Cpu::setRAM(GIGA_CH0_KEY_H + i*GIGA_CHANNEL_OFFSET, 0x00); // high frequency look up from ROM
|
|
Cpu::setRAM(GIGA_CH0_OSC_L + i*GIGA_CHANNEL_OFFSET, 0x00); // low internal oscillator
|
|
Cpu::setRAM(GIGA_CH0_OSC_H + i*GIGA_CHANNEL_OFFSET, 0x00); // high internal oscillator
|
|
}
|
|
}
|
|
|
|
|
|
void fillCallbackBuffer(void)
|
|
{
|
|
_audioSamples[_audioInIndex++ % AUDIO_BUFFER_SIZE] = (Cpu::getXOUT() & XOUT_MASK) <<6;
|
|
}
|
|
|
|
void fillBuffer(void)
|
|
{
|
|
_audioSamples[_audioInIndex++] = (Cpu::getXOUT() & XOUT_MASK) <<6;
|
|
if(_audioInIndex == AUDIO_SAMPLES)
|
|
{
|
|
playBuffer();
|
|
_audioInIndex = 0;
|
|
}
|
|
}
|
|
|
|
void playBuffer(void)
|
|
{
|
|
SDL_QueueAudio(_audioDevice, &_audioSamples[0], uint32_t(_audioInIndex) <<1);
|
|
_audioInIndex = 0;
|
|
}
|
|
|
|
void playSample(void)
|
|
{
|
|
uint16_t sample = (Cpu::getXOUT() & XOUT_MASK) <<6;
|
|
SDL_QueueAudio(_audioDevice, &sample, 2);
|
|
}
|
|
|
|
void clearQueue(void)
|
|
{
|
|
SDL_ClearQueuedAudio(_audioDevice);
|
|
}
|
|
|
|
|
|
//**********************************************************************************************************************
|
|
//* Editor
|
|
//**********************************************************************************************************************
|
|
#ifndef STAND_ALONE
|
|
enum MenuItem {MenuLoadMidi=0, MenuLoadWave, MenuSaveWave, MenuEraseWave};
|
|
enum DialogItem {DialogFile=2, DialogNo=5, DialogYes=6};
|
|
enum WaveIndex {WaveUser=0, Wave0, Wave1, Wave2, Wave3};
|
|
enum SuffixType {GtWav=0, GtMid, GtMidi};
|
|
enum CmdLineType {CmdLineWave, CmdLineMidi, NumCmdLineTypes};
|
|
enum LeaveMode {LeavePrev, LeaveHex, LeaveDasm, LeaveImage, LeaveTerm, LeaveLoad};
|
|
|
|
const std::vector<std::string> _waveStrs = {"User", "Wav0", "Wav1", "Wav2", "Wav3"};
|
|
const std::vector<std::string> _suffixes = {".gtwav", ".gtmid", ".gtmidi"};
|
|
const std::string _eraseLine = std::string(MAX_COMMAND_CHARS+1, 32);
|
|
|
|
std::string _browserPath, _browserPathBackup;
|
|
|
|
bool _firstTimeRender = true;
|
|
bool _refreshScreen = false;
|
|
bool _midiPlaying = false;
|
|
bool _midiLineMode = false;
|
|
|
|
uint8_t _waveUser[MAX_WAVE_X] = {0};
|
|
uint8_t _waveBuffer[MAX_WAVE_X] = {0};
|
|
uint8_t _midiBuffer[MIDI_MAX_BUFFER_SIZE] = {0};
|
|
int _midiBufferSize = 0;
|
|
|
|
int _waveIndex = WaveUser;
|
|
int _commandCharIndex[NumCmdLineTypes] = {0};
|
|
std::string _commandLine[NumCmdLineTypes];
|
|
CmdLineType _cmdLineType = CmdLineMidi;
|
|
|
|
Editor::MouseState _mouseState;
|
|
|
|
|
|
void initialiseEditor(void)
|
|
{
|
|
// Menu
|
|
std::vector<std::string> menuItems = {" AUDIO ", "Load Midi", "Load Wave", "Save Wave", "Del Wave"};
|
|
Menu::createMenu("Audio", menuItems, 9, 5);
|
|
|
|
// Overwrite dialog
|
|
std::vector<Dialog::Item> dialogItems =
|
|
{
|
|
Dialog::Item(false, "Overwrite?"),
|
|
Dialog::Item(false, ""),
|
|
Dialog::Item(false, ""),
|
|
Dialog::Item(false, ""),
|
|
Dialog::Item(false, ""),
|
|
Dialog::Item(true, "No", Dialog::Item::LeftX, Dialog::Item::Bd),
|
|
Dialog::Item(true, "Yes", Dialog::Item::RightX, Dialog::Item::CurrentY, Dialog::Item::Bd)
|
|
};
|
|
Dialog::createDialog("Overwrite", "Overwrite", dialogItems, 3, 5, Dialog::Dialog::DoubleWidth, 0, 1);
|
|
|
|
// Wave
|
|
dialogItems = {Dialog::Item(false, "Wave")};
|
|
Dialog::createDialog("Wave", "Wave", dialogItems, 4, 1, Dialog::Dialog::Regular, 1, 0, 106, 60);
|
|
Dialog::positionDialog("Wave", 1, BORDER_Y1);
|
|
dialogItems = {Dialog::Item(false, "Load")};
|
|
Dialog::createDialog("LoadW", "Load", dialogItems, 4, 1, Dialog::Dialog::Regular, 1, 0, 106, 60);
|
|
Dialog::positionDialog("LoadW", 1, BORDER_Y1 + 6);
|
|
|
|
// Play Wave
|
|
dialogItems = {Dialog::Item(true, "Play", Dialog::Item::CenterX, Dialog::Item::NextY, Dialog::Item::Bd)};
|
|
Dialog::createDialog("PlayW", "Play", dialogItems, 5, 1, Dialog::Dialog::Regular, 1, 0, 106, 60);
|
|
|
|
// Reset Wave
|
|
dialogItems = {Dialog::Item(true, "Reset", Dialog::Item::CenterX, Dialog::Item::NextY, Dialog::Item::Bd)};
|
|
Dialog::createDialog("Reset", "Reset", dialogItems, 5, 1, Dialog::Dialog::Regular, 1, 0, 106, 60);
|
|
Dialog::positionDialog("Reset", 78, BOTTOM_ROW);
|
|
|
|
// Erase Wave
|
|
dialogItems = {Dialog::Item(true, "Erase", Dialog::Item::CenterX, Dialog::Item::NextY, Dialog::Item::Bd)};
|
|
Dialog::createDialog("Erase", "Erase", dialogItems, 5, 1, Dialog::Dialog::Regular, 1, 0, 106, 60);
|
|
Dialog::positionDialog("Erase", 84, BOTTOM_ROW);
|
|
|
|
// Prev Wave
|
|
dialogItems = {Dialog::Item(true, "Prev", Dialog::Item::CenterX, Dialog::Item::NextY, Dialog::Item::Bd)};
|
|
Dialog::createDialog("Prev", "Prev", dialogItems, 4, 1, Dialog::Dialog::Regular, 1, 0, 106, 60);
|
|
Dialog::positionDialog("Prev", 15, BOTTOM_ROW);
|
|
|
|
// Next Wave
|
|
dialogItems = {Dialog::Item(true, "Next", Dialog::Item::CenterX, Dialog::Item::NextY, Dialog::Item::Bd)};
|
|
Dialog::createDialog("Next", "Next", dialogItems, 4, 1, Dialog::Dialog::Regular, 1, 0, 106, 60);
|
|
Dialog::positionDialog("Next", 132, BOTTOM_ROW);
|
|
|
|
// Midi
|
|
dialogItems = {Dialog::Item(false, "Midi")};
|
|
Dialog::createDialog("Midi", "Midi", dialogItems, 4, 1, Dialog::Dialog::Regular, 1, 0, 106, 60);
|
|
Dialog::positionDialog("Midi", 1, 1);
|
|
dialogItems = {Dialog::Item(true, "Play", Dialog::Item::CenterX, Dialog::Item::NextY, Dialog::Item::Bd)};
|
|
Dialog::createDialog("PlayM", "Play", dialogItems, 4, 1, Dialog::Dialog::Regular, 1, 0, 106, 60);
|
|
Dialog::positionDialog("PlayM", 71, 1);
|
|
dialogItems = {Dialog::Item(true, "4Bit", Dialog::Item::CenterX, Dialog::Item::NextY, Dialog::Item::Bd)};
|
|
Dialog::createDialog("6Bit", "4Bit", dialogItems, 4, 1, Dialog::Dialog::Regular, 1, 0, 106, 60);
|
|
Dialog::positionDialog("6Bit", 132, 1);
|
|
dialogItems = {Dialog::Item(true, "Pixel", Dialog::Item::CenterX, Dialog::Item::NextY, Dialog::Item::Bd)};
|
|
Dialog::createDialog("LineM", "Pixel", dialogItems, 4, 1, Dialog::Dialog::Regular, 1, 0, 106, 60);
|
|
Dialog::positionDialog("LineM", 115, 1);
|
|
|
|
_browserPath = Editor::getBrowserPath();
|
|
}
|
|
|
|
void leave(LeaveMode leaveMode)
|
|
{
|
|
Midi::stop();
|
|
_firstTimeRender = true;
|
|
Editor::setBrowserPath(_browserPathBackup);
|
|
|
|
switch(leaveMode)
|
|
{
|
|
case LeavePrev: Editor::setEditorToPrevMode(); break;
|
|
case LeaveHex: Editor::setEditorMode(Editor::Hex); break;
|
|
case LeaveDasm: Editor::setEditorMode(Editor::Dasm); break;
|
|
case LeaveImage: Editor::setEditorMode(Editor::Image); break;
|
|
case LeaveTerm: Terminal::switchToTerminal(); break;
|
|
|
|
case LeaveLoad:
|
|
{
|
|
Editor::setEditorMode(Editor::Load);
|
|
Editor::browseDirectory();
|
|
}
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
|
|
void clearCommandLine(void)
|
|
{
|
|
_commandCharIndex[_cmdLineType] = 0;
|
|
_commandLine[_cmdLineType].clear();
|
|
}
|
|
|
|
void prevCommandLineChar(void)
|
|
{
|
|
if(--_commandCharIndex[_cmdLineType] < 0) _commandCharIndex[_cmdLineType] = 0;
|
|
}
|
|
|
|
void nextCommandLineChar(void)
|
|
{
|
|
if(++_commandCharIndex[_cmdLineType] > int(_commandLine[_cmdLineType].size())) _commandCharIndex[_cmdLineType] = int(_commandLine[_cmdLineType].size());
|
|
}
|
|
|
|
void homeCommandLineChar(void)
|
|
{
|
|
_commandCharIndex[_cmdLineType] = 0;
|
|
}
|
|
|
|
void endCommandLineChar(void)
|
|
{
|
|
_commandCharIndex[_cmdLineType] = (_commandLine[_cmdLineType].size()) ? int(_commandLine[_cmdLineType].size()) - 1 : 0;
|
|
}
|
|
|
|
void backspaceCommandLineChar(void)
|
|
{
|
|
if(_commandLine[_cmdLineType].size() && _commandCharIndex[_cmdLineType] > 0 && _commandCharIndex[_cmdLineType] <= int(_commandLine[_cmdLineType].size()))
|
|
{
|
|
_commandLine[_cmdLineType].erase(--_commandCharIndex[_cmdLineType], 1);
|
|
}
|
|
}
|
|
|
|
void deleteCommandLineChar(void)
|
|
{
|
|
if(_commandLine[_cmdLineType].size() && _commandCharIndex[_cmdLineType] >= 0 && _commandCharIndex[_cmdLineType] < int(_commandLine[_cmdLineType].size()))
|
|
{
|
|
_commandLine[_cmdLineType].erase(_commandCharIndex[_cmdLineType], 1);
|
|
if(_commandCharIndex[_cmdLineType] > int(_commandLine[_cmdLineType].size())) _commandCharIndex[_cmdLineType] = int(_commandLine[_cmdLineType].size());
|
|
}
|
|
}
|
|
|
|
void copyWaveTable(uint8_t src[], uint8_t dst[])
|
|
{
|
|
for(uint16_t i=0; i<MAX_WAVE_X; i++)
|
|
{
|
|
dst[i] = src[i];
|
|
}
|
|
}
|
|
|
|
void loadWaveTable(uint16_t wave)
|
|
{
|
|
wave = wave & 3;
|
|
uint16_t address = 0x0700 + wave;
|
|
for(uint16_t i=0; i<MAX_WAVE_X; i++)
|
|
{
|
|
_waveBuffer[i] = Cpu::getRAM(address + i*4);
|
|
}
|
|
}
|
|
|
|
void uploadWaveTable(uint16_t waveTable, uint8_t waveBuffer[])
|
|
{
|
|
int j = 0;
|
|
waveTable = waveTable & 3;
|
|
for(uint16_t i=waveTable; i<256; i+=4) Cpu::setRAM(0x0700 + i, waveBuffer[j++]);
|
|
}
|
|
|
|
void playNote(uint8_t wave, uint16_t note, int duration)
|
|
{
|
|
wave = wave & 3;
|
|
Cpu::setRAM(GIGA_CH0_WAV_X, wave);
|
|
|
|
Cpu::setRAM(GIGA_SOUND_TIMER, uint8_t(duration));
|
|
|
|
note = (note - 11) * 2;
|
|
uint16_t romNote = Cpu::getROM16(note + 0x0900, 1);
|
|
Cpu::setRAM16(GIGA_CH0_KEY_L, romNote);
|
|
|
|
while(Cpu::getRAM(GIGA_SOUND_TIMER))
|
|
{
|
|
Cpu::process(true);
|
|
}
|
|
}
|
|
|
|
void refreshScreen(void)
|
|
{
|
|
_firstTimeRender = false;
|
|
_refreshScreen = false;
|
|
|
|
Graphics::clearScreen(0x22222222);
|
|
Graphics::drawLine(0, 43, GIGA_WIDTH-1, 43, 0x00000000);
|
|
Graphics::drawLine(0, 119, GIGA_WIDTH-1, 119, 0x00000000);
|
|
|
|
// Midi waveform window
|
|
Graphics::drawLine(BORDER_X1, 39, BORDER_X2, 39, 0x88888888);
|
|
Graphics::drawLine(BORDER_X1, 6, BORDER_X1, 39, 0x88888888);
|
|
Graphics::drawLine(BORDER_X1, 6, BORDER_X2, 6, 0x88888888);
|
|
Graphics::drawLine(BORDER_X2, 6, BORDER_X2, 39, 0x88888888);
|
|
|
|
// Wave waveform window
|
|
Graphics::drawLine(BORDER_X1, BORDER_Y2, BORDER_X2, BORDER_Y2, 0x88888888);
|
|
Graphics::drawLine(BORDER_X1, BORDER_Y1, BORDER_X1, BORDER_Y2, 0x88888888);
|
|
Graphics::drawLine(BORDER_X1, BORDER_Y1, BORDER_X2, BORDER_Y1, 0x88888888);
|
|
Graphics::drawLine(BORDER_X2, BORDER_Y1, BORDER_X2, BORDER_Y2, 0x88888888);
|
|
|
|
Editor::browseDirectory(_suffixes);
|
|
_browserPath = Editor::getBrowserPath();
|
|
}
|
|
|
|
void refreshWave(void)
|
|
{
|
|
Graphics::rectFill(BORDER_X1+1, BORDER_Y1+1, BORDER_X2, BORDER_Y2, 0x33333333);
|
|
for(int i=0; i<MAX_WAVE_X; i++)
|
|
{
|
|
Graphics::drawPixel(uint8_t((BORDER_X1 + 1) + i*2), uint8_t((BORDER_Y2 - 1) - (_waveBuffer[i] & 63)), 0xBBBBBBBB);
|
|
Graphics::drawPixel(uint8_t((BORDER_X1 + 1) + i*2 + 1), uint8_t((BORDER_Y2 - 1) - (_waveBuffer[i] & 63)), 0xBBBBBBBB);
|
|
}
|
|
}
|
|
|
|
void refreshMidi(void)
|
|
{
|
|
Graphics::rectFill(BORDER_X1+1, 7, BORDER_X2, 39, 0x33333333);
|
|
int end = (_midiLineMode) ? 127 : 128;
|
|
for(int i=0; i<end; i++) // AUDIO_BUFFER_SIZE = 2048
|
|
{
|
|
uint8_t sample0 = (_audioSamples[(i+0) <<2] >>9) & 31;
|
|
uint8_t sample1 = (_audioSamples[(i+1) <<2] >>9) & 31;
|
|
if(_midiLineMode)
|
|
{
|
|
Graphics::drawLine(uint8_t((BORDER_X1 + 1) + i), uint8_t(38 - sample0), uint8_t((BORDER_X1 + 1) + i + 1), uint8_t(38 - sample1), 0xBBBBBBBB);
|
|
}
|
|
else
|
|
{
|
|
Graphics::drawPixel(uint8_t((BORDER_X1 + 1) + i), uint8_t(38 - sample0), 0xBBBBBBBB);
|
|
}
|
|
}
|
|
}
|
|
|
|
void refreshCommandLine(CmdLineType cmdLineType)
|
|
{
|
|
int row = (_cmdLineType == CmdLineWave) ? WAVE_TEXT_ROW : MIDI_TEXT_ROW;
|
|
|
|
std::string commandLine = _commandLine[cmdLineType];
|
|
if(_commandCharIndex[cmdLineType] >= int(commandLine.size()))
|
|
{
|
|
_commandCharIndex[cmdLineType] = int(commandLine.size());
|
|
commandLine += char(32);
|
|
}
|
|
Graphics::drawText(_eraseLine, 0, row, 0x55555555, true, MAX_COMMAND_CHARS+1);
|
|
|
|
// Flash wave cursor, refreshUi() is run 60 times per second
|
|
static uint8_t toggle = 0;
|
|
bool invert = ((toggle++) >>4) & 1;
|
|
Graphics::drawText(commandLine, FONT_WIDTH, row, 0xFFFFFFFF, invert, 1, _commandCharIndex[cmdLineType]);
|
|
}
|
|
|
|
void refreshUi(void)
|
|
{
|
|
// Update wave
|
|
Dialog::Item dialogItem;
|
|
Dialog::getDialogItem("LoadW", 0, dialogItem);
|
|
dialogItem.setText(_waveStrs[_waveIndex]);
|
|
Dialog::setDialogItem("LoadW", 0, dialogItem);
|
|
Dialog::renderDialog("Wave", 0, 0);
|
|
Dialog::renderDialog("LoadW", 0, 0);
|
|
|
|
// Wave interactables
|
|
Dialog::renderDialog("Prev", _mouseState._x, _mouseState._y);
|
|
Dialog::renderDialog("Next", _mouseState._x, _mouseState._y);
|
|
if(!_waveIndex)
|
|
{
|
|
Dialog::positionDialog("PlayW", 63, BOTTOM_ROW);
|
|
Dialog::renderDialog("PlayW", _mouseState._x, _mouseState._y);
|
|
Dialog::positionDialog("Erase", 78, BOTTOM_ROW);
|
|
Dialog::renderDialog("Erase", _mouseState._x, _mouseState._y);
|
|
}
|
|
else
|
|
{
|
|
Dialog::positionDialog("PlayW", 55, BOTTOM_ROW);
|
|
Dialog::renderDialog("PlayW", _mouseState._x, _mouseState._y);
|
|
Dialog::positionDialog("Reset", 69, BOTTOM_ROW);
|
|
Dialog::renderDialog("Reset", _mouseState._x, _mouseState._y);
|
|
Dialog::positionDialog("Erase", 85, BOTTOM_ROW);
|
|
Dialog::renderDialog("Erase", _mouseState._x, _mouseState._y);
|
|
}
|
|
|
|
// Midi
|
|
Dialog::renderDialog("Midi", 0, 0);
|
|
Dialog::renderDialog("PlayM", _mouseState._x, _mouseState._y);
|
|
Dialog::renderDialog("6Bit", _mouseState._x, _mouseState._y);
|
|
Dialog::renderDialog("LineM", _mouseState._x, _mouseState._y);
|
|
|
|
// Command line
|
|
refreshCommandLine(_cmdLineType);
|
|
}
|
|
|
|
void chooseCmdLineOnMouse(int mouseX, int mouseY)
|
|
{
|
|
static CmdLineType cmdLineType = _cmdLineType;
|
|
|
|
// Normalised mouse position
|
|
float mx = float(mouseX) / float(Graphics::getWidth()) * 4.0f/3.0f;
|
|
float my = float(mouseY) / float(Graphics::getHeight());
|
|
int pixelX = int(mx * float(GIGA_WIDTH));
|
|
int pixelY = int(my * float(GIGA_HEIGHT));
|
|
if(pixelX > 0 && pixelX < GIGA_WIDTH)
|
|
{
|
|
if(pixelY < 42) _cmdLineType = CmdLineMidi;
|
|
if(pixelY > 42) _cmdLineType = CmdLineWave;
|
|
}
|
|
|
|
if(cmdLineType != _cmdLineType)
|
|
{
|
|
_refreshScreen = true;
|
|
cmdLineType = _cmdLineType;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
bool isMouseInWave(int mouseX, int mouseY, int& pixelX, int& pixelY)
|
|
{
|
|
Menu::Menu menu;
|
|
if(Menu::getMenu("Audio", menu))
|
|
{
|
|
if(menu.getIsActive()) return false;
|
|
}
|
|
|
|
// Normalised mouse position
|
|
float mx = float(mouseX) / float(Graphics::getWidth()) * 4.0f/3.0f;
|
|
float my = float(mouseY) / float(Graphics::getHeight());
|
|
pixelX = int(mx * float(GIGA_WIDTH));
|
|
pixelY = int(my * float(GIGA_HEIGHT));
|
|
if(pixelX > BORDER_X1 && pixelX < BORDER_X2 && pixelY > BORDER_Y1 && pixelY < BORDER_Y2)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void handleGuiEvents(SDL_Event& event)
|
|
{
|
|
switch(event.type)
|
|
{
|
|
case SDL_WINDOWEVENT:
|
|
{
|
|
switch(event.window.event)
|
|
{
|
|
case SDL_WINDOWEVENT_RESIZED:
|
|
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
|
{
|
|
Graphics::setWidthHeight(event.window.data1, event.window.data2);
|
|
}
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SDL_QUIT:
|
|
{
|
|
Cpu::shutdown();
|
|
exit(0);
|
|
}
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
void handleNonModalDialogs(void)
|
|
{
|
|
// Save user wave
|
|
if(_waveIndex == WaveUser)
|
|
{
|
|
copyWaveTable(_waveBuffer, _waveUser);
|
|
}
|
|
|
|
if(Dialog::getDialogItemIndex("Prev", _mouseState._x, _mouseState._y) != -1)
|
|
{
|
|
if(--_waveIndex < WaveUser) _waveIndex = Wave3;
|
|
if(_waveIndex) loadWaveTable(uint16_t(_waveIndex - 1));
|
|
}
|
|
else if(Dialog::getDialogItemIndex("Next", _mouseState._x, _mouseState._y) != -1)
|
|
{
|
|
if(++_waveIndex > Wave3) _waveIndex = WaveUser;
|
|
if(_waveIndex) loadWaveTable(uint16_t(_waveIndex - 1));
|
|
}
|
|
else if(Dialog::getDialogItemIndex("PlayW", _mouseState._x, _mouseState._y) != -1)
|
|
{
|
|
// Play internal wave
|
|
if(_waveIndex)
|
|
{
|
|
playNote(uint8_t(_waveIndex - 1), 60, 30);
|
|
}
|
|
// Upload user wave to internal wave 0 play it, then restore
|
|
else
|
|
{
|
|
uploadWaveTable(0, _waveBuffer);
|
|
playNote(0, 60, 30);
|
|
restoreWaveTable(0);
|
|
}
|
|
}
|
|
else if(Dialog::getDialogItemIndex("PlayM", _mouseState._x, _mouseState._y) != -1)
|
|
{
|
|
_midiPlaying = !_midiPlaying;
|
|
Midi::pause(!_midiPlaying);
|
|
if(_midiPlaying)
|
|
{
|
|
Dialog::positionDialog("PlayM", 70, 1);
|
|
Dialog::setDialogItemText("PlayM", 0, "Pause");
|
|
if(Midi::getStream() == nullptr && _midiBuffer)
|
|
{
|
|
Midi::setStream(nullptr, _midiBuffer, uint16_t(_midiBufferSize));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Dialog::positionDialog("PlayM", 71, 1);
|
|
Dialog::setDialogItemText("PlayM", 0, "Play");
|
|
}
|
|
}
|
|
else if(Dialog::getDialogItemIndex("6Bit", _mouseState._x, _mouseState._y) != -1)
|
|
{
|
|
static bool quality = false;
|
|
quality = !quality;
|
|
if(!quality)
|
|
{
|
|
Cpu::enable6BitSound(Cpu::ROMv5a, false);
|
|
Dialog::setDialogItemText("6Bit", 0, "4Bit");
|
|
}
|
|
else
|
|
{
|
|
Cpu::enable6BitSound(Cpu::ROMv5a, true);
|
|
Dialog::setDialogItemText("6Bit", 0, "6Bit");
|
|
}
|
|
}
|
|
else if(Dialog::getDialogItemIndex("LineM", _mouseState._x, _mouseState._y) != -1)
|
|
{
|
|
_midiLineMode = !_midiLineMode;
|
|
(_midiLineMode) ? Dialog::setDialogItemText("LineM", 0, "Line ") : Dialog::setDialogItemText("LineM", 0, "Pixel");
|
|
}
|
|
else if(Dialog::getDialogItemIndex("Reset", _mouseState._x, _mouseState._y) != -1)
|
|
{
|
|
if(_waveIndex)
|
|
{
|
|
restoreWaveTable(uint16_t(_waveIndex - 1));
|
|
loadWaveTable(uint16_t(_waveIndex - 1));
|
|
}
|
|
}
|
|
else if(Dialog::getDialogItemIndex("Erase", _mouseState._x, _mouseState._y) != -1)
|
|
{
|
|
if(_waveIndex)
|
|
{
|
|
for(int i=0; i<MAX_WAVE_X; i++) _waveBuffer[i] = 0;
|
|
uploadWaveTable(int16_t(_waveIndex - 1), _waveBuffer);
|
|
}
|
|
else
|
|
{
|
|
for(int i=0; i<MAX_WAVE_X; i++) _waveUser[i] = 0;
|
|
}
|
|
_refreshScreen = true;
|
|
}
|
|
|
|
// Restore user wave
|
|
if(_waveIndex == WaveUser)
|
|
{
|
|
copyWaveTable(_waveUser, _waveBuffer);
|
|
}
|
|
}
|
|
|
|
int handleModalDialog(const std::string& name)
|
|
{
|
|
// Mouse button state
|
|
_mouseState._state = SDL_GetMouseState(&_mouseState._x, &_mouseState._y);
|
|
|
|
SDL_Event event;
|
|
int dialogItem = -1;
|
|
while(SDL_PollEvent(&event))
|
|
{
|
|
_mouseState._state = SDL_GetMouseState(&_mouseState._x, &_mouseState._y);
|
|
|
|
handleGuiEvents(event);
|
|
|
|
switch(event.type)
|
|
{
|
|
case SDL_MOUSEBUTTONUP: dialogItem = Dialog::getDialogItemIndex(name, _mouseState._x, _mouseState._y); break;
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
return dialogItem;
|
|
}
|
|
|
|
bool loadWaveFile(std::string* filenamePtr)
|
|
{
|
|
if(filenamePtr == nullptr && _commandLine[CmdLineWave].size() == 0)
|
|
{
|
|
fprintf(stderr, "Audio::loadWaveFile() : no file to load\n");
|
|
return false;
|
|
}
|
|
|
|
// Browser get priority over command line
|
|
std::string filename;
|
|
if(filenamePtr != nullptr)
|
|
{
|
|
filename = *filenamePtr;
|
|
_commandLine[CmdLineWave] = filename;
|
|
_commandCharIndex[CmdLineWave] = (_commandLine[CmdLineWave].size()) ? int(_commandLine[CmdLineWave].size()) : 0;
|
|
}
|
|
else
|
|
{
|
|
filename = _commandLine[CmdLineWave];
|
|
}
|
|
|
|
// Read
|
|
std::string filepath = _browserPath + filename;
|
|
std::ifstream infile(filepath, std::ios::binary | std::ios::in);
|
|
if(!infile.is_open())
|
|
{
|
|
fprintf(stderr, "Audio::loadWaveFile() : failed to open file '%s' for reading\n", filepath.c_str());
|
|
return false;
|
|
}
|
|
|
|
infile.read((char *)&_waveBuffer, MAX_WAVE_X);
|
|
if(infile.bad() || infile.fail())
|
|
{
|
|
fprintf(stderr, "Audio::loadWaveFile() : read error in file '%s'\n", filepath.c_str());
|
|
return false;
|
|
}
|
|
|
|
if(_waveIndex) uploadWaveTable(int16_t(_waveIndex - 1), _waveBuffer);
|
|
|
|
_cmdLineType = CmdLineWave;
|
|
|
|
//fprintf(stderr, "Audio::loadWaveFile() : Loaded wave file '%s'\n", filepath.c_str());
|
|
return true;
|
|
}
|
|
|
|
bool saveWaveFile(void)
|
|
{
|
|
if(_commandLine[CmdLineWave].size() == 0)
|
|
{
|
|
fprintf(stderr, "Audio::saveWaveFile() : no file to save\n");
|
|
return false;
|
|
}
|
|
|
|
std::string filepath = _browserPath + _commandLine[CmdLineWave];
|
|
|
|
// Detect overwrite
|
|
std::ifstream infile(filepath, std::ios::binary | std::ios::in);
|
|
if(infile.is_open())
|
|
{
|
|
_refreshScreen = true;
|
|
refreshScreen();
|
|
refreshWave();
|
|
|
|
// Update dialog filename item
|
|
Dialog::Item dialogItem;
|
|
Dialog::getDialogItem("Overwrite", DialogFile, dialogItem);
|
|
dialogItem.setText(_commandLine[CmdLineWave]);
|
|
Dialog::setDialogItem("Overwrite", DialogFile, dialogItem);
|
|
Dialog::positionDialog("Overwrite", 62, 50);
|
|
|
|
int dialogItemIndex = -1;
|
|
do
|
|
{
|
|
Editor::getMouseState(_mouseState);
|
|
dialogItemIndex = handleModalDialog("Overwrite");
|
|
Dialog::renderDialog("Overwrite", _mouseState._x, _mouseState._y);
|
|
Graphics::render(true);
|
|
}
|
|
while(dialogItemIndex == -1);
|
|
infile.close();
|
|
|
|
if(dialogItemIndex == DialogNo) return false;
|
|
}
|
|
|
|
// Write
|
|
std::ofstream outfile(filepath, std::ios::binary | std::ios::out);
|
|
if(!outfile.is_open())
|
|
{
|
|
fprintf(stderr, "Audio::saveWaveFile() : failed to open file for writing '%s' for writing\n", filepath.c_str());
|
|
return false;
|
|
}
|
|
|
|
outfile.write((char *)&_waveBuffer, MAX_WAVE_X);
|
|
if(outfile.bad() || outfile.fail())
|
|
{
|
|
fprintf(stderr, "Audio::saveWaveFile() : write error in file '%s'\n", filepath.c_str());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool loadMidiFile(const std::string* filenamePtr)
|
|
{
|
|
Audio::initialiseChannels();
|
|
|
|
std::string filename;
|
|
if(filenamePtr != nullptr)
|
|
{
|
|
filename = *filenamePtr;
|
|
_commandLine[CmdLineMidi] = filename;
|
|
_commandCharIndex[CmdLineMidi] = (_commandLine[CmdLineMidi].size()) ? int(_commandLine[CmdLineMidi].size()) : 0;
|
|
}
|
|
|
|
if(filename == "")
|
|
{
|
|
fprintf(stderr, "Audio::loadMidiFile() : no file to load\n");
|
|
return false;
|
|
}
|
|
|
|
// Read
|
|
std::string filepath = _browserPath + filename;
|
|
if(!Midi::loadFile(filepath, _midiBuffer, _midiBufferSize)) return false;
|
|
if(!Midi::setStream(filenamePtr, _midiBuffer, uint16_t(_midiBufferSize))) return false;
|
|
|
|
Dialog::positionDialog("PlayM", 70, 1);
|
|
Dialog::setDialogItemText("PlayM", 0, "Pause");
|
|
_midiPlaying = true;
|
|
_cmdLineType = CmdLineMidi;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool loadCorrectFileType(std::string* filenamePtr)
|
|
{
|
|
if(filenamePtr == nullptr)
|
|
{
|
|
switch(_cmdLineType)
|
|
{
|
|
case CmdLineMidi: return loadMidiFile(filenamePtr); break;
|
|
case CmdLineWave: return loadWaveFile(filenamePtr); break;
|
|
|
|
default: break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
for(int i=0; i<int(_suffixes.size()); i++)
|
|
{
|
|
std::string name = Expression::strUpper(*filenamePtr);
|
|
std::string suffix = Expression::strUpper(_suffixes[i]);
|
|
if(name.find(suffix) != std::string::npos)
|
|
{
|
|
switch(i)
|
|
{
|
|
case GtMid:
|
|
case GtMidi: return loadMidiFile(filenamePtr); break;
|
|
case GtWav: return loadWaveFile(filenamePtr); break;
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void handleMenu(void)
|
|
{
|
|
Menu::Menu menu;
|
|
if(!Menu::getMenu("Audio", menu)) return;
|
|
|
|
int menuItemIndex;
|
|
Menu::getMenuItemIndex("Audio", menuItemIndex);
|
|
switch(menuItemIndex)
|
|
{
|
|
case MenuLoadMidi: loadMidiFile(nullptr); break;
|
|
case MenuLoadWave: loadWaveFile(nullptr); break;
|
|
case MenuSaveWave: saveWaveFile(); break;
|
|
|
|
case MenuEraseWave:
|
|
{
|
|
for(int i=0; i<MAX_WAVE_X; i++) _waveBuffer[i] = 0;
|
|
if(_waveIndex)
|
|
{
|
|
uploadWaveTable(int16_t(_waveIndex - 1), _waveBuffer);
|
|
}
|
|
else
|
|
{
|
|
copyWaveTable(_waveBuffer, _waveUser);
|
|
}
|
|
_refreshScreen = true;
|
|
}
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
void handleMouseLeftButtonDown(void)
|
|
{
|
|
chooseCmdLineOnMouse(_mouseState._x, _mouseState._y);
|
|
|
|
int pixelX, pixelY;
|
|
if(isMouseInWave(_mouseState._x, _mouseState._y, pixelX, pixelY))
|
|
{
|
|
_waveBuffer[(pixelX - (BORDER_X1 + 1))/2] = uint8_t(64 - (pixelY - BORDER_Y1));
|
|
if(_waveIndex) uploadWaveTable(int16_t(_waveIndex - 1), _waveBuffer);
|
|
_refreshScreen = true;
|
|
}
|
|
}
|
|
|
|
void handleMouseRightButtonDown(void)
|
|
{
|
|
chooseCmdLineOnMouse(_mouseState._x, _mouseState._y);
|
|
|
|
int pixelX, pixelY;
|
|
if(isMouseInWave(_mouseState._x, _mouseState._y, pixelX, pixelY))
|
|
{
|
|
_waveBuffer[(pixelX - (BORDER_X1 + 1))/2] = 0;
|
|
if(_waveIndex) uploadWaveTable(int16_t(_waveIndex - 1), _waveBuffer);
|
|
_refreshScreen = true;
|
|
}
|
|
else
|
|
{
|
|
Menu::captureItem("Audio", _mouseState._x, _mouseState._y);
|
|
Menu::renderMenu("Audio");
|
|
}
|
|
}
|
|
|
|
void handleMouseButtonDown(const SDL_Event& event)
|
|
{
|
|
UNREFERENCED_PARAM(event);
|
|
|
|
if(_mouseState._state == SDL_BUTTON_LEFT)
|
|
{
|
|
// Handle browse UI
|
|
if(Editor::getPageUpButton())
|
|
{
|
|
Editor::handleBrowsePageUp(HEX_CHARS_Y);
|
|
}
|
|
else if(Editor::getPageDnButton())
|
|
{
|
|
Editor::handleBrowsePageDown(HEX_CHARS_Y);
|
|
}
|
|
// No loading/browsing if cursor is out of bounds
|
|
else if(Editor::getCursorY() < 0 || Editor::getCursorY() >= Editor::getFileEntriesSize())
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
Editor::FileType fileType = Editor::getCurrentFileEntryType();
|
|
switch(fileType)
|
|
{
|
|
case Editor::File: loadCorrectFileType(Editor::getCurrentFileEntryName()); break;
|
|
case Editor::Dir: Editor::changeBrowseDirectory(); break;
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
_refreshScreen = true;
|
|
}
|
|
|
|
if(_mouseState._state == SDL_BUTTON_X1)
|
|
{
|
|
Menu::captureMenu("Audio", _mouseState._x, _mouseState._y);
|
|
}
|
|
}
|
|
|
|
void handleMouseButtonUp(const SDL_Event& event)
|
|
{
|
|
UNREFERENCED_PARAM(event);
|
|
|
|
handleMenu();
|
|
handleNonModalDialogs();
|
|
|
|
_refreshScreen = true;
|
|
}
|
|
|
|
void handleMouseWheel(const SDL_Event& event)
|
|
{
|
|
if(event.wheel.y > 0) Editor::handleBrowsePageUp(1);
|
|
if(event.wheel.y < 0) Editor::handleBrowsePageDown(1);
|
|
|
|
_refreshScreen = true;
|
|
}
|
|
|
|
void handleKey(const SDL_Event& event)
|
|
{
|
|
char keyCode = event.text.text[0];
|
|
|
|
if(keyCode >= 32 && keyCode <= 126)
|
|
{
|
|
// Accept alpha for first char and alphanumeric or underscore or period for rest
|
|
if((_commandLine[_cmdLineType].size() == 0 && _commandCharIndex[_cmdLineType] == 0 && (isalpha(keyCode) || keyCode == 32)) ||
|
|
(_commandLine[_cmdLineType].size() != 0 && (isalnum(keyCode) || keyCode == 32 || keyCode == '_' || keyCode == '.')))
|
|
{
|
|
// Max of one period in a filename
|
|
if(keyCode == '.' && std::count(_commandLine[_cmdLineType].begin(), _commandLine[_cmdLineType].end(), '.') == 1) return;
|
|
|
|
if(_commandLine[_cmdLineType].size() >= MAX_COMMAND_CHARS-1) return;
|
|
|
|
_commandLine[_cmdLineType].insert(_commandLine[_cmdLineType].begin() + _commandCharIndex[_cmdLineType], char(keyCode));
|
|
_commandCharIndex[_cmdLineType]++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void handleKeyDown(SDL_Keycode keyCode, Uint16 keyMod)
|
|
{
|
|
// Leave audio editor
|
|
if(keyCode == Editor::getEmulatorScanCode("AudioEditor") && keyMod == Editor::getEmulatorKeyMod("AudioEditor"))
|
|
{
|
|
leave(LeavePrev);
|
|
}
|
|
// Quit
|
|
else if(keyCode == Editor::getEmulatorScanCode("Quit") && keyMod == Editor::getEmulatorKeyMod("Quit"))
|
|
{
|
|
Cpu::shutdown();
|
|
exit(0);
|
|
}
|
|
// Image editor
|
|
else if(keyCode == Editor::getEmulatorScanCode("ImageEditor") && keyMod == Editor::getEmulatorKeyMod("ImageEditor"))
|
|
{
|
|
leave(LeaveImage);
|
|
}
|
|
// Terminal mode
|
|
else if(keyCode == Editor::getEmulatorScanCode("Terminal") && keyMod == Editor::getEmulatorKeyMod("Terminal"))
|
|
{
|
|
leave(LeaveTerm);
|
|
}
|
|
|
|
if(keyMod == 0x0000)
|
|
{
|
|
switch(keyCode)
|
|
{
|
|
case SDLK_LEFT: prevCommandLineChar(); break;
|
|
case SDLK_RIGHT: nextCommandLineChar(); break;
|
|
case SDLK_HOME: homeCommandLineChar(); break;
|
|
case SDLK_END: endCommandLineChar(); break;
|
|
case SDLK_DELETE: deleteCommandLineChar(); break;
|
|
case SDLK_BACKSPACE: backspaceCommandLineChar(); break;
|
|
|
|
case '\r':
|
|
case '\n': loadCorrectFileType(&_commandLine[_cmdLineType]);
|
|
|
|
default : break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void handleKeyUp(SDL_Keycode keyCode, Uint16 keyMod)
|
|
{
|
|
// Help screen
|
|
if(keyCode == Editor::getEmulatorScanCode("Help") && keyMod == Editor::getEmulatorKeyMod("Help"))
|
|
{
|
|
static bool helpScreen = false;
|
|
helpScreen = !helpScreen;
|
|
Graphics::setDisplayHelpScreen(helpScreen);
|
|
}
|
|
// Disassembler
|
|
else if(keyCode == Editor::getEmulatorScanCode("Disassembler") && keyMod == Editor::getEmulatorKeyMod("Disassembler"))
|
|
{
|
|
leave(LeaveDasm);
|
|
}
|
|
// Browser
|
|
else if(keyCode == Editor::getEmulatorScanCode("Browse") && keyMod == Editor::getEmulatorKeyMod("Browse"))
|
|
{
|
|
leave(LeaveLoad);
|
|
}
|
|
// Hex monitor
|
|
else if(keyCode == Editor::getEmulatorScanCode("HexMonitor") && keyMod == Editor::getEmulatorKeyMod("HexMonitor"))
|
|
{
|
|
leave(LeaveHex);
|
|
}
|
|
}
|
|
|
|
void handleInput(void)
|
|
{
|
|
// Mouse button state
|
|
_mouseState._state = SDL_GetMouseState(&_mouseState._x, &_mouseState._y);
|
|
|
|
//chooseCmdLineOnMouse(_mouseState._x, _mouseState._y);
|
|
|
|
SDL_Event event;
|
|
while(SDL_PollEvent(&event))
|
|
{
|
|
SDL_Keycode keyCode = event.key.keysym.sym;
|
|
Uint16 keyMod = event.key.keysym.mod & (KMOD_LCTRL | KMOD_LALT | KMOD_LSHIFT);
|
|
|
|
_mouseState._state = SDL_GetMouseState(&_mouseState._x, &_mouseState._y);
|
|
Editor::setMouseState(_mouseState);
|
|
|
|
handleGuiEvents(event);
|
|
|
|
switch(event.type)
|
|
{
|
|
case SDL_MOUSEBUTTONDOWN: handleMouseButtonDown(event); break;
|
|
case SDL_MOUSEBUTTONUP: handleMouseButtonUp(event); break;
|
|
case SDL_MOUSEWHEEL: handleMouseWheel(event); break;
|
|
case SDL_TEXTINPUT: handleKey(event); break;
|
|
case SDL_KEYDOWN: handleKeyDown(keyCode, keyMod); break;
|
|
case SDL_KEYUP: handleKeyUp(keyCode, keyMod); break;
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
switch(_mouseState._state)
|
|
{
|
|
case SDL_BUTTON_LEFT: handleMouseLeftButtonDown(); break;
|
|
case SDL_BUTTON_X1: handleMouseRightButtonDown(); break;
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
void process(void)
|
|
{
|
|
bool vBlank = false;
|
|
|
|
if(_firstTimeRender)
|
|
{
|
|
_browserPathBackup = Editor::getBrowserPath();
|
|
Editor::setBrowserPath(_browserPath);
|
|
|
|
refreshScreen();
|
|
}
|
|
if(_refreshScreen) refreshScreen();
|
|
|
|
if(Midi::getStream())
|
|
{
|
|
vBlank = Cpu::process(true);
|
|
if(vBlank) Midi::play();
|
|
}
|
|
|
|
if(Midi::getStream() == nullptr && _midiPlaying)
|
|
{
|
|
refreshScreen();
|
|
_midiPlaying = false;
|
|
Dialog::positionDialog("PlayM", 71, 1);
|
|
Dialog::setDialogItemText("PlayM", 0, "Play");
|
|
}
|
|
|
|
if(Midi::getStream() == nullptr || vBlank)
|
|
{
|
|
refreshWave();
|
|
refreshMidi();
|
|
refreshUi();
|
|
|
|
handleInput();
|
|
Graphics::render(!vBlank);
|
|
}
|
|
}
|
|
#endif
|
|
}
|