Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repos:
hooks:
- id: flake8
args:
- --max-complexity=30
- --max-complexity=50
- --max-line-length=456
- --show-source
- --statistics
2 changes: 2 additions & 0 deletions cnds/cnds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ NB_MODULE(cnds, m) {
.def("get_gba_frame", &Nds::getGbaFrame)
.def("get_top_nds_frame", &Nds::getTopNdsFrame)
.def("get_bot_nds_frame", &Nds::getBotNdsFrame)
.def("get_audio_samples", &Nds::getAudioSamples)
.def("get_audio_buffer_number", &Nds::getAudioBufferNumber)

// Save methods
.def("save_state", &Nds::saveState)
Expand Down
4 changes: 4 additions & 0 deletions cnds/include/nds.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ class Nds {
nb::ndarray<nb::numpy, uint8_t> getTopNdsFrame();
nb::ndarray<nb::numpy, uint8_t> getBotNdsFrame();

// Audio methods
nb::ndarray<nb::numpy, int16_t> getAudioSamples(int count);
uint32_t getAudioBufferNumber();

// Savestate methods
void saveState(std::string path);
void loadState(std::string path);
Expand Down
17 changes: 17 additions & 0 deletions cnds/nds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,23 @@ nb::ndarray<nb::numpy, uint8_t> Nds::getBotNdsFrame() {
}
}

nb::ndarray<nb::numpy, int16_t> Nds::getAudioSamples(int count) {
uint32_t* raw = m_core->spu.getSamples(count);
int16_t* samples = new int16_t[count * 2];
for (int i = 0; i < count; i++) {
samples[i * 2] = (int16_t)(raw[i] & 0xFFFF);
samples[i * 2 + 1] = (int16_t)((raw[i] >> 16) & 0xFFFF);
}
nb::capsule owner(samples, [](void* p) noexcept {
delete[] (int16_t*)p;
});
return nb::ndarray<nb::numpy, int16_t>(samples, {(size_t)count, 2}, owner);
}

uint32_t Nds::getAudioBufferNumber() {
return m_core->spu.getBufferNumber();
}

void Nds::saveState(std::string path) {
m_core->saveStates.setPath(path, m_isGba);
m_core->saveStates.saveState();
Expand Down
2 changes: 1 addition & 1 deletion externals/NooDS
Submodule NooDS updated 3 files
+1 −1 src/settings.cpp
+7 −0 src/spu.cpp
+2 −0 src/spu.h
37 changes: 37 additions & 0 deletions pynds/audio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import time
import threading

import sounddevice as sd
import numpy as np


class Audio:
def __init__(self, pynds) -> None:
self._pynds = pynds

self.running = False

def start(self) -> None:
self.stream = sd.OutputStream(samplerate=32768, channels=2, dtype='int16', blocksize=0)
self.running = True

self.audio_thread = threading.Thread(target=self.play_audio)
self.audio_thread.start()

def close(self) -> None:
if (self.running):
self.running = False
self.audio_thread.join()

def play_audio(self):
self.stream.start()

while (self.running):
samples = self._pynds.get_audio(699)
data_to_write = np.ascontiguousarray(samples)
self.stream.write(data_to_write)

time.sleep(0.001)

self.stream.stop()
self.stream.close()
17 changes: 17 additions & 0 deletions pynds/pynds.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .memory import Memory
from .button import Button
from .window import Window
from .audio import Audio
from .config import config


Expand All @@ -23,6 +24,7 @@ def __init__(self, path: str, save_path: str = "", auto_detect: bool = True, is_
self.button = Button(self._nds)
self.memory = Memory(self._nds)
self.window = Window(self)
self.audio = Audio(self)

def get_is_gba(self) -> bool:
return self.is_gba
Expand Down Expand Up @@ -54,6 +56,12 @@ def get_frame_shape(self) -> Tuple[int, int]:
else:
return (NDS[0]*scale, NDS[1]*scale, 4)

def get_audio(self, count: int = 699) -> np.ndarray:
return self._nds.get_audio_samples(count)

def get_audio_buffer_number(self) -> int:
return self._nds.get_audio_buffer_number()

def open_window(self, width: int = 800, height: int = 800) -> None:
if (self.window.running):
self.window.close()
Expand All @@ -63,6 +71,15 @@ def open_window(self, width: int = 800, height: int = 800) -> None:
def close_window(self) -> None:
self.window.close()

def open_audio(self) -> None:
if (self.audio.running):
self.audio.close()

self.audio.start()

def close_audio(self) -> None:
self.audio.close()

def render(self) -> None:
if (self.window.running):
self.window.render()
Expand Down
4 changes: 1 addition & 3 deletions pynds/window.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import pygame
import numpy as np
import pygame


class Window:
Expand All @@ -13,7 +13,6 @@ def init(self, width: int, height: int) -> None:
pygame.init()
self.screen = pygame.display.set_mode((width, height), pygame.RESIZABLE)
pygame.display.set_caption("PyNDS")

self.running = True

def close(self) -> None:
Expand Down Expand Up @@ -137,5 +136,4 @@ def process_frame_nds(self):
surface = pygame.image.frombuffer(frame_bot, (frame_bot.shape[0], frame_bot.shape[1]), 'RGBA')
surface = pygame.transform.scale(surface, (width, height // 2))
self.screen.blit(surface, surface.get_rect(topleft=(0, height // 2)))

pygame.display.flip()
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def build_extensions(self):

setup(name='pynds',
packages=find_packages(),
install_requires=['numpy', 'pygame'],
install_requires=['numpy', 'pygame', 'sounddevice'],
version=version,
description='Python bindings for NooDS',
author='unexploredtest',
Expand Down
Loading