mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2024-11-14 05:17:40 -07:00
Compare commits
3 Commits
6bc78f198d
...
ab5a992d34
Author | SHA1 | Date | |
---|---|---|---|
|
ab5a992d34 | ||
|
5e8beb3ab7 | ||
|
44e6dec81e |
2
BUILD.md
2
BUILD.md
@ -47,7 +47,7 @@
|
||||
1. Install Qt: `pacman -S <prefix>-{qt6-base,qt6-svg,qt6-multimedia,qt6-svg,qt6-tools}`
|
||||
2. Set up the build directory with `cmake -B build`
|
||||
* Static builds (without DLLs, standalone executable)
|
||||
1. Install Qt: `pacman -S <prefi>-qt5-static`
|
||||
1. Install Qt: `pacman -S <prefix>-qt5-static`
|
||||
(Note: As of writing, the `qt6-static` package does not work.)
|
||||
2. Set up the build directory with `cmake -B build -DBUILD_STATIC=ON -DUSE_QT6=OFF -DCMAKE_PREFIX_PATH=$MSYSTEM_PREFIX/qt5-static`
|
||||
7. Compile: `cmake --build build`
|
||||
|
@ -21,6 +21,7 @@ add_library(core STATIC
|
||||
DSi_Camera.cpp
|
||||
DSi_DSP.cpp
|
||||
DSi_I2C.cpp
|
||||
DSi_I2S.cpp
|
||||
DSi_NAND.cpp
|
||||
DSi_NDMA.cpp
|
||||
DSi_NWifi.cpp
|
||||
|
77
src/DSi.cpp
77
src/DSi.cpp
@ -35,6 +35,7 @@
|
||||
|
||||
#include "DSi_NDMA.h"
|
||||
#include "DSi_I2C.h"
|
||||
#include "DSi_I2S.h"
|
||||
#include "DSi_SD.h"
|
||||
#include "DSi_AES.h"
|
||||
#include "DSi_NAND.h"
|
||||
@ -108,6 +109,7 @@ DSi::DSi(DSiArgs&& args, void* userdata) noexcept :
|
||||
SDMMC(*this, std::move(args.NANDImage), std::move(args.DSiSDCard)),
|
||||
SDIO(*this),
|
||||
I2C(*this),
|
||||
I2S(*this),
|
||||
CamModule(*this),
|
||||
AES(*this)
|
||||
{
|
||||
@ -141,6 +143,7 @@ void DSi::Reset()
|
||||
for (int i = 0; i < 8; i++) NDMAs[i].Reset();
|
||||
|
||||
I2C.Reset();
|
||||
I2S.Reset();
|
||||
CamModule.Reset();
|
||||
DSP.Reset();
|
||||
|
||||
@ -210,6 +213,13 @@ void DSi::CamInputFrame(int cam, const u32* data, int width, int height, bool rg
|
||||
}
|
||||
}
|
||||
|
||||
void DSi::MicInputFrame(s16* data, int samples)
|
||||
{
|
||||
SPI.GetTSC()->MicInputFrame(data, samples);
|
||||
I2S.MicInputFrame(data, samples);
|
||||
// TODO: Need to send the mic samples to the DSP!
|
||||
}
|
||||
|
||||
void DSi::DoSavestateExtra(Savestate* file)
|
||||
{
|
||||
file->Section("DSIG");
|
||||
@ -285,6 +295,7 @@ void DSi::DoSavestateExtra(Savestate* file)
|
||||
CamModule.DoSavestate(file);
|
||||
DSP.DoSavestate(file);
|
||||
I2C.DoSavestate(file);
|
||||
I2S.DoSavestate(file);
|
||||
SDMMC.DoSavestate(file);
|
||||
SDIO.DoSavestate(file);
|
||||
}
|
||||
@ -644,6 +655,8 @@ void DSi::SetupDirectBoot()
|
||||
|
||||
SPI.GetFirmwareMem()->SetupDirectBoot();
|
||||
|
||||
I2S.WriteSndExCnt(0x8008, 0xFFFF);
|
||||
|
||||
ARM9.CP15Write(0x100, 0x00056078);
|
||||
ARM9.CP15Write(0x200, 0x0000004A);
|
||||
ARM9.CP15Write(0x201, 0x0000004A);
|
||||
@ -690,6 +703,9 @@ void DSi::SoftReset()
|
||||
|
||||
NDS::MapSharedWRAM(3);
|
||||
|
||||
// TODO: is this actually reset?
|
||||
I2S.Reset();
|
||||
|
||||
// TODO: does the DSP get reset? NWRAM doesn't, so I'm assuming no
|
||||
// *HOWEVER*, the bootrom (which does get rerun) does remap NWRAM, and thus
|
||||
// the DSP most likely gets reset
|
||||
@ -2707,8 +2723,16 @@ u8 DSi::ARM7IORead8(u32 addr)
|
||||
case 0x04004D07: if (SCFG_BIOS & (1<<10)) return 0; return SDMMC.GetNAND()->GetConsoleID() >> 56;
|
||||
case 0x04004D08: return 0;
|
||||
|
||||
case 0x4004700: return DSP.ReadSNDExCnt() & 0xFF;
|
||||
case 0x4004701: return DSP.ReadSNDExCnt() >> 8;
|
||||
case 0x4004600: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicCnt() & 0xFF;
|
||||
case 0x4004601: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicCnt() >> 8;
|
||||
case 0x4004602: return 0;
|
||||
case 0x4004603: return 0;
|
||||
case 0x4004604: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicData() & 0xFF;
|
||||
case 0x4004605: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return (I2S.ReadMicData() >> 8) & 0xFF;
|
||||
case 0x4004606: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return (I2S.ReadMicData() >> 16) & 0xFF;
|
||||
case 0x4004607: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicData() >> 24;
|
||||
case 0x4004700: if (!(SCFG_EXT[1] & (1 << 21))) return 0; return I2S.ReadSndExCnt() & 0xFF;
|
||||
case 0x4004701: if (!(SCFG_EXT[1] & (1 << 21))) return 0; return I2S.ReadSndExCnt() >> 8;
|
||||
|
||||
case 0x04004C00: return GPIO_Data;
|
||||
case 0x04004C01: return GPIO_Dir;
|
||||
@ -2751,7 +2775,11 @@ u16 DSi::ARM7IORead16(u32 addr)
|
||||
case 0x04004D06: if (SCFG_BIOS & (1<<10)) return 0; return SDMMC.GetNAND()->GetConsoleID() >> 48;
|
||||
case 0x04004D08: return 0;
|
||||
|
||||
case 0x4004700: return DSP.ReadSNDExCnt();
|
||||
case 0x4004600: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicCnt();
|
||||
case 0x4004602: return 0;
|
||||
case 0x4004604: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicData() >> 16;
|
||||
case 0x4004606: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicData() & 0xFFFF;
|
||||
case 0x4004700: if (!(SCFG_EXT[1] & (1 << 21))) return 0; return I2S.ReadSndExCnt();
|
||||
|
||||
case 0x04004C00: return GPIO_Data | ((u16)GPIO_Dir << 8);
|
||||
case 0x04004C02: return GPIO_IEdgeSel | ((u16)GPIO_IE << 8);
|
||||
@ -2829,9 +2857,9 @@ u32 DSi::ARM7IORead32(u32 addr)
|
||||
case 0x04004D04: if (SCFG_BIOS & (1<<10)) return 0; return SDMMC.GetNAND()->GetConsoleID() >> 32;
|
||||
case 0x04004D08: return 0;
|
||||
|
||||
case 0x4004700:
|
||||
Log(LogLevel::Debug, "32-Bit SNDExCnt read? %08X\n", ARM7.R[15]);
|
||||
return DSP.ReadSNDExCnt();
|
||||
case 0x4004600: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicCnt();
|
||||
case 0x4004604: if (!(SCFG_EXT[1] & (1 << 20))) return 0; return I2S.ReadMicData();
|
||||
case 0x4004700: if (!(SCFG_EXT[1] & (1 << 21))) return 0; return I2S.ReadSndExCnt();
|
||||
}
|
||||
|
||||
if (addr >= 0x04004800 && addr < 0x04004A00)
|
||||
@ -2884,11 +2912,25 @@ void DSi::ARM7IOWrite8(u32 addr, u8 val)
|
||||
case 0x04004500: I2C.WriteData(val); return;
|
||||
case 0x04004501: I2C.WriteCnt(val); return;
|
||||
|
||||
case 0x4004600:
|
||||
if (!(SCFG_EXT[1] & (1 << 20)))
|
||||
return;
|
||||
I2S.WriteMicCnt((u16)val, 0xFF);
|
||||
return;
|
||||
case 0x4004601:
|
||||
if (!(SCFG_EXT[1] & (1 << 20)))
|
||||
return;
|
||||
I2S.WriteMicCnt(((u16)val << 8), 0xFF00);
|
||||
return;
|
||||
case 0x4004700:
|
||||
DSP.WriteSNDExCnt((u16)val, 0xFF);
|
||||
if (!(SCFG_EXT[1] & (1 << 21)))
|
||||
return;
|
||||
I2S.WriteSndExCnt((u16)val, 0xFF);
|
||||
return;
|
||||
case 0x4004701:
|
||||
DSP.WriteSNDExCnt(((u16)val << 8), 0xFF00);
|
||||
if (!(SCFG_EXT[1] & (1 << 21)))
|
||||
return;
|
||||
I2S.WriteSndExCnt(((u16)val << 8), 0xFF00);
|
||||
return;
|
||||
|
||||
case 0x04004C00:
|
||||
@ -2987,8 +3029,15 @@ void DSi::ARM7IOWrite16(u32 addr, u16 val)
|
||||
AES.WriteBlkCnt(val<<16);
|
||||
return;
|
||||
|
||||
case 0x4004600:
|
||||
if (!(SCFG_EXT[1] & (1 << 20)))
|
||||
return;
|
||||
I2S.WriteMicCnt(val, 0xFFFF);
|
||||
return;
|
||||
case 0x4004700:
|
||||
DSP.WriteSNDExCnt(val, 0xFFFF);
|
||||
if (!(SCFG_EXT[1] & (1 << 21)))
|
||||
return;
|
||||
I2S.WriteSndExCnt(val, 0xFFFF);
|
||||
return;
|
||||
|
||||
case 0x04004C00:
|
||||
@ -3136,9 +3185,15 @@ void DSi::ARM7IOWrite32(u32 addr, u32 val)
|
||||
case 0x04004404: AES.WriteBlkCnt(val); return;
|
||||
case 0x04004408: AES.WriteInputFIFO(val); return;
|
||||
|
||||
case 0x4004600:
|
||||
if (!(SCFG_EXT[1] & (1 << 20)))
|
||||
return;
|
||||
I2S.WriteMicCnt(val, 0xFFFF);
|
||||
return;
|
||||
case 0x4004700:
|
||||
Log(LogLevel::Debug, "32-Bit SNDExCnt write? %08X %08X\n", val, ARM7.R[15]);
|
||||
DSP.WriteSNDExCnt(val, 0xFFFF);
|
||||
if (!(SCFG_EXT[1] & (1 << 21)))
|
||||
return;
|
||||
I2S.WriteSndExCnt(val, 0xFFFF);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "NDS.h"
|
||||
#include "DSi_NDMA.h"
|
||||
#include "DSi_I2S.h"
|
||||
#include "DSi_SD.h"
|
||||
#include "DSi_DSP.h"
|
||||
#include "DSi_AES.h"
|
||||
@ -30,6 +31,7 @@
|
||||
namespace melonDS
|
||||
{
|
||||
class DSi_I2CHost;
|
||||
class DSi_I2S;
|
||||
class DSi_CamModule;
|
||||
class DSi_AES;
|
||||
class DSi_DSP;
|
||||
@ -69,6 +71,7 @@ public:
|
||||
u32 NWRAMMask[2][3];
|
||||
|
||||
DSi_I2CHost I2C;
|
||||
DSi_I2S I2S;
|
||||
DSi_CamModule CamModule;
|
||||
DSi_AES AES;
|
||||
DSi_DSP DSP;
|
||||
@ -155,6 +158,7 @@ public:
|
||||
void SetSDCard(std::optional<FATStorage>&& sdcard) noexcept { SDMMC.SetSDCard(std::move(sdcard)); }
|
||||
|
||||
void CamInputFrame(int cam, const u32* data, int width, int height, bool rgb) override;
|
||||
void MicInputFrame(s16* data, int samples) override;
|
||||
bool DMAsInMode(u32 cpu, u32 mode) const override;
|
||||
bool DMAsRunning(u32 cpu) const override;
|
||||
void StopDMAs(u32 cpu, u32 mode) override;
|
||||
|
@ -178,8 +178,6 @@ void DSi_DSP::Reset()
|
||||
TeakraCore->Reset();
|
||||
|
||||
DSi.CancelEvent(Event_DSi_DSP);
|
||||
|
||||
SNDExCnt = 0;
|
||||
}
|
||||
|
||||
bool DSi_DSP::IsRstReleased() const
|
||||
@ -536,23 +534,6 @@ void DSi_DSP::Write32(u32 addr, u32 val)
|
||||
Write16(addr, val & 0xFFFF);
|
||||
}
|
||||
|
||||
void DSi_DSP::WriteSNDExCnt(u16 val, u16 mask)
|
||||
{
|
||||
val = (val & mask) | (SNDExCnt & ~mask);
|
||||
|
||||
// it can be written even in NDS mode
|
||||
|
||||
// mic frequency can only be changed if it was disabled
|
||||
// before the write
|
||||
if (SNDExCnt & 0x8000)
|
||||
{
|
||||
val &= ~0x2000;
|
||||
val |= SNDExCnt & 0x2000;
|
||||
}
|
||||
|
||||
SNDExCnt = val & 0xE00F;
|
||||
}
|
||||
|
||||
void DSi_DSP::Run(u32 cycles)
|
||||
{
|
||||
if (!IsDSPCoreEnabled())
|
||||
|
@ -54,9 +54,6 @@ public:
|
||||
u32 Read32(u32 addr);
|
||||
void Write32(u32 addr, u32 val);
|
||||
|
||||
u16 ReadSNDExCnt() const { return SNDExCnt; }
|
||||
void WriteSNDExCnt(u16 val, u16 mask);
|
||||
|
||||
// NOTE: checks SCFG_CLK9
|
||||
void Run(u32 cycles);
|
||||
|
||||
@ -70,8 +67,6 @@ public:
|
||||
|
||||
private:
|
||||
melonDS::DSi& DSi;
|
||||
// not sure whether to not rather put it somewhere else
|
||||
u16 SNDExCnt;
|
||||
|
||||
Teakra::Teakra* TeakraCore;
|
||||
|
||||
|
219
src/DSi_I2S.cpp
Normal file
219
src/DSi_I2S.cpp
Normal file
@ -0,0 +1,219 @@
|
||||
/*
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS 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 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "DSi.h"
|
||||
#include "DSi_I2S.h"
|
||||
#include "Platform.h"
|
||||
|
||||
namespace melonDS
|
||||
{
|
||||
using Platform::Log;
|
||||
using Platform::LogLevel;
|
||||
|
||||
|
||||
DSi_I2S::DSi_I2S(melonDS::DSi& dsi) : DSi(dsi)
|
||||
{
|
||||
DSi.RegisterEventFunc(Event_DSi_I2S, 0, MemberEventFunc(DSi_I2S, Clock));
|
||||
|
||||
MicCnt = 0;
|
||||
SndExCnt = 0;
|
||||
MicClockDivider = 0;
|
||||
|
||||
MicBufferLen = 0;
|
||||
}
|
||||
|
||||
DSi_I2S::~DSi_I2S()
|
||||
{
|
||||
DSi.UnregisterEventFunc(Event_DSi_I2S, 0);
|
||||
}
|
||||
|
||||
void DSi_I2S::Reset()
|
||||
{
|
||||
MicCnt = 0;
|
||||
SndExCnt = 0;
|
||||
MicClockDivider = 0;
|
||||
|
||||
MicFifo.Clear();
|
||||
|
||||
MicBufferLen = 0;
|
||||
|
||||
DSi.ScheduleEvent(Event_DSi_I2S, false, 1024, 0, I2S_Freq_32728Hz);
|
||||
}
|
||||
|
||||
void DSi_I2S::DoSavestate(Savestate* file)
|
||||
{
|
||||
file->Section("I2Si");
|
||||
|
||||
file->Var16(&MicCnt);
|
||||
file->Var16(&SndExCnt);
|
||||
file->Var8(&MicClockDivider);
|
||||
|
||||
MicFifo.DoSavestate(file);
|
||||
}
|
||||
|
||||
void DSi_I2S::MicInputFrame(const s16* data, int samples)
|
||||
{
|
||||
if (!data)
|
||||
{
|
||||
MicBufferLen = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (samples > 1024) samples = 1024;
|
||||
memcpy(MicBuffer, data, samples * sizeof(s16));
|
||||
MicBufferLen = samples;
|
||||
}
|
||||
|
||||
u16 DSi_I2S::ReadMicCnt()
|
||||
{
|
||||
u16 ret = MicCnt;
|
||||
if (MicFifo.Level() == 0) ret |= 1 << 8;
|
||||
if (MicFifo.Level() >= 16) ret |= 1 << 9;
|
||||
if (MicFifo.Level() >= 32) ret |= 1 << 10;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DSi_I2S::WriteMicCnt(u16 val, u16 mask)
|
||||
{
|
||||
val = (val & mask) | (MicCnt & ~mask);
|
||||
|
||||
// FIFO clear can only happen if the mic was disabled before the write
|
||||
if (!(MicCnt & (1 << 15)) && (val & (1 << 12)))
|
||||
{
|
||||
MicCnt &= ~(1 << 11);
|
||||
MicFifo.Clear();
|
||||
}
|
||||
|
||||
MicCnt = (val & 0xE00F) | (MicCnt & (1 << 11));
|
||||
}
|
||||
|
||||
u32 DSi_I2S::ReadMicData()
|
||||
{
|
||||
// CHECKME: This is a complete guess on how mic data reads work
|
||||
// gbatek states the FIFO is 16 words large, with 1 word having 2 samples
|
||||
u32 ret = MicFifo.IsEmpty() ? 0 : (u16)MicFifo.Read();
|
||||
ret |= (MicFifo.IsEmpty() ? 0 : (u16)MicFifo.Read()) << 16;
|
||||
return ret;
|
||||
}
|
||||
|
||||
u16 DSi_I2S::ReadSndExCnt()
|
||||
{
|
||||
return SndExCnt;
|
||||
}
|
||||
|
||||
void DSi_I2S::WriteSndExCnt(u16 val, u16 mask)
|
||||
{
|
||||
val = (val & mask) | (SndExCnt & ~mask);
|
||||
|
||||
// Note: SNDEXCNT can be accessed in "NDS mode"
|
||||
// This is due to the corresponding SCFG_EXT flag not being disabled
|
||||
// If it is disabled (with homebrew), SNDEXCNT cannot be accessed
|
||||
// This is more purely a software mistake on the DSi menu's part
|
||||
|
||||
// I2S frequency can only be changed if it was disabled before the write
|
||||
if (SndExCnt & (1 << 15))
|
||||
{
|
||||
val &= ~(1 << 13);
|
||||
val |= SndExCnt & (1 << 13);
|
||||
}
|
||||
|
||||
if ((SndExCnt ^ val) & (1 << 13))
|
||||
{
|
||||
Log(LogLevel::Debug, "Changed I2S frequency to %dHz\n", (SndExCnt & (1 << 13)) ? 47605 : 32728);
|
||||
}
|
||||
|
||||
SndExCnt = val & 0xE00F;
|
||||
}
|
||||
|
||||
void DSi_I2S::Clock(u32 freq)
|
||||
{
|
||||
if (SndExCnt & (1 << 15))
|
||||
{
|
||||
// CHECKME (from gbatek)
|
||||
// "The Sampling Rate becomes zero (no data arriving) when SNDEXCNT.Bit15=0, or when MIC_CNT.bit0-1=3, or when MIC_CNT.bit15=0, or when Overrun has occurred."
|
||||
// This likely means on any of these conditions the mic completely ignores any I2S clocks
|
||||
// Although perhaps it might still acknowledge the clocks in some capacity (maybe affecting below clock division)
|
||||
if ((MicCnt & (1 << 15)) && !(MicCnt & (1 << 11)) && (MicCnt & 3) != 3)
|
||||
{
|
||||
// CHECKME (from gbatek)
|
||||
// "2-3 Sampling Rate (0..3=F/1, F/2, F/3, F/4)"
|
||||
// This likely works with an internal counter compared with the sampling rate
|
||||
// This counter is then likely reset on mic sample
|
||||
// But this is completely untested
|
||||
|
||||
MicClockDivider++;
|
||||
u8 micRate = (MicCnt >> 2) & 3;
|
||||
if (MicClockDivider > micRate)
|
||||
{
|
||||
MicClockDivider = 0;
|
||||
|
||||
s16 sample = 0;
|
||||
if (MicBufferLen > 0)
|
||||
{
|
||||
// 560190 cycles per frame
|
||||
u32 cyclepos = (u32)DSi.GetSysClockCycles(2);
|
||||
u32 samplepos = (cyclepos * MicBufferLen) / 560190;
|
||||
if (samplepos >= MicBufferLen) samplepos = MicBufferLen - 1;
|
||||
sample = MicBuffer[samplepos];
|
||||
}
|
||||
|
||||
u32 oldLevel = MicFifo.Level();
|
||||
if ((MicCnt & 3) == 0)
|
||||
{
|
||||
// stereo (this just duplicates the sample, as the mic itself is mono)
|
||||
if (MicFifo.IsFull()) MicCnt |= 1 << 11;
|
||||
MicFifo.Write(sample);
|
||||
if (MicFifo.IsFull()) MicCnt |= 1 << 11;
|
||||
MicFifo.Write(sample);
|
||||
}
|
||||
else
|
||||
{
|
||||
// mono
|
||||
if (MicFifo.IsFull()) MicCnt |= 1 << 11;
|
||||
MicFifo.Write(sample);
|
||||
}
|
||||
|
||||
// if bit 13 is set, an IRQ is generated when the mic FIFO is half full
|
||||
if (MicCnt & (1 << 13))
|
||||
{
|
||||
if (oldLevel < 16 && MicFifo.Level() >= 16) DSi.SetIRQ2(IRQ2_DSi_MicExt);
|
||||
}
|
||||
// if bit 13 is not set and bit 14 is set, an IRQ is generated when the mic FIFO is full
|
||||
else if (MicCnt & (1 << 14))
|
||||
{
|
||||
if (oldLevel < 32 && MicFifo.Level() >= 32) DSi.SetIRQ2(IRQ2_DSi_MicExt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: SPU and DSP sampling should happen here
|
||||
// use passed freq to know how much to advance SPU by?
|
||||
}
|
||||
|
||||
if (SndExCnt & (1 << 13))
|
||||
{
|
||||
DSi.ScheduleEvent(Event_DSi_I2S, false, 704, 0, I2S_Freq_47605Hz);
|
||||
}
|
||||
else
|
||||
{
|
||||
DSi.ScheduleEvent(Event_DSi_I2S, false, 1024, 0, I2S_Freq_32728Hz);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
68
src/DSi_I2S.h
Normal file
68
src/DSi_I2S.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright 2016-2024 melonDS team
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS 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 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef DSI_I2S_H
|
||||
#define DSI_I2S_H
|
||||
|
||||
#include "FIFO.h"
|
||||
#include "types.h"
|
||||
#include "Savestate.h"
|
||||
|
||||
namespace melonDS
|
||||
{
|
||||
class DSi;
|
||||
class DSi_I2S
|
||||
{
|
||||
public:
|
||||
DSi_I2S(melonDS::DSi& dsi);
|
||||
~DSi_I2S();
|
||||
void Reset();
|
||||
void DoSavestate(Savestate* file);
|
||||
|
||||
void MicInputFrame(const s16* data, int samples);
|
||||
|
||||
u16 ReadMicCnt();
|
||||
void WriteMicCnt(u16 val, u16 mask);
|
||||
|
||||
u32 ReadMicData();
|
||||
|
||||
u16 ReadSndExCnt();
|
||||
void WriteSndExCnt(u16 val, u16 mask);
|
||||
|
||||
private:
|
||||
melonDS::DSi& DSi;
|
||||
|
||||
u16 MicCnt;
|
||||
u16 SndExCnt;
|
||||
u8 MicClockDivider;
|
||||
FIFO<s16, 32> MicFifo;
|
||||
|
||||
s16 MicBuffer[1024];
|
||||
int MicBufferLen;
|
||||
|
||||
enum
|
||||
{
|
||||
I2S_Freq_32728Hz,
|
||||
I2S_Freq_47605Hz
|
||||
};
|
||||
|
||||
void Clock(u32 freq);
|
||||
};
|
||||
|
||||
}
|
||||
#endif // DSI_I2S_H
|
@ -72,6 +72,7 @@ enum
|
||||
Event_DSi_CamIRQ,
|
||||
Event_DSi_CamTransfer,
|
||||
Event_DSi_DSP,
|
||||
Event_DSi_I2S,
|
||||
|
||||
Event_MAX
|
||||
};
|
||||
@ -400,7 +401,7 @@ public: // TODO: Encapsulate the rest of these members
|
||||
void SetLidClosed(bool closed);
|
||||
|
||||
virtual void CamInputFrame(int cam, const u32* data, int width, int height, bool rgb) {}
|
||||
void MicInputFrame(s16* data, int samples);
|
||||
virtual void MicInputFrame(s16* data, int samples);
|
||||
|
||||
void RegisterEventFunc(u32 id, u32 funcid, EventFunc func);
|
||||
void UnregisterEventFunc(u32 id, u32 funcid);
|
||||
|
Loading…
Reference in New Issue
Block a user