mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 19:50:12 +01:00
add better WASAPI
This commit is contained in:
@@ -101,8 +101,8 @@ def main():
|
|||||||
ray.toggle_fullscreen()
|
ray.toggle_fullscreen()
|
||||||
|
|
||||||
next_screen = screen.update()
|
next_screen = screen.update()
|
||||||
screen.draw()
|
|
||||||
ray.clear_background(ray.BLACK)
|
ray.clear_background(ray.BLACK)
|
||||||
|
screen.draw()
|
||||||
|
|
||||||
if next_screen is not None:
|
if next_screen is not None:
|
||||||
current_screen = next_screen
|
current_screen = next_screen
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import time
|
|||||||
import wave
|
import wave
|
||||||
from threading import Lock, Thread
|
from threading import Lock, Thread
|
||||||
|
|
||||||
import pyray as ray
|
|
||||||
from numpy import (
|
from numpy import (
|
||||||
abs as np_abs,
|
abs as np_abs,
|
||||||
)
|
)
|
||||||
@@ -413,10 +412,10 @@ class Music:
|
|||||||
except Exception:
|
except Exception:
|
||||||
raise Exception("unable to close music stream")
|
raise Exception("unable to close music stream")
|
||||||
|
|
||||||
class ASIOEngine:
|
class AudioEngine:
|
||||||
def __init__(self):
|
def __init__(self, type: str):
|
||||||
self.target_sample_rate = 48000
|
self.target_sample_rate = 48000
|
||||||
self.buffer_size = get_config()["audio"]["asio_buffer"]
|
self.buffer_size = get_config()["audio"]["buffer_size"]
|
||||||
self.sounds = {}
|
self.sounds = {}
|
||||||
self.music_streams = {}
|
self.music_streams = {}
|
||||||
self.stream = None
|
self.stream = None
|
||||||
@@ -431,6 +430,7 @@ class ASIOEngine:
|
|||||||
# Threading for music stream updates
|
# Threading for music stream updates
|
||||||
self.update_thread = None
|
self.update_thread = None
|
||||||
self.update_thread_running = False
|
self.update_thread_running = False
|
||||||
|
self.type = type
|
||||||
|
|
||||||
def _initialize_asio(self):
|
def _initialize_asio(self):
|
||||||
"""Set up ASIO device"""
|
"""Set up ASIO device"""
|
||||||
@@ -438,11 +438,12 @@ class ASIOEngine:
|
|||||||
hostapis = sd.query_hostapis()
|
hostapis = sd.query_hostapis()
|
||||||
asio_api_index = -1
|
asio_api_index = -1
|
||||||
for i, api in enumerate(hostapis):
|
for i, api in enumerate(hostapis):
|
||||||
if isinstance(api, dict) and 'name' in api and api['name'] == 'ASIO':
|
if isinstance(api, dict) and 'name' in api and api['name'] == self.type:
|
||||||
asio_api_index = i
|
asio_api_index = i
|
||||||
break
|
break
|
||||||
|
|
||||||
if asio_api_index is not None:
|
print(hostapis)
|
||||||
|
if isinstance(hostapis, tuple):
|
||||||
asio_api = hostapis[asio_api_index]
|
asio_api = hostapis[asio_api_index]
|
||||||
if isinstance(asio_api, dict) and 'default_output_device' in asio_api:
|
if isinstance(asio_api, dict) and 'default_output_device' in asio_api:
|
||||||
default_asio_device = asio_api['default_output_device']
|
default_asio_device = asio_api['default_output_device']
|
||||||
@@ -460,8 +461,6 @@ class ASIOEngine:
|
|||||||
# Limit to stereo for simplicity
|
# Limit to stereo for simplicity
|
||||||
self.output_channels = 2
|
self.output_channels = 2
|
||||||
return True
|
return True
|
||||||
else:
|
|
||||||
print("No default ASIO device found, using system default.")
|
|
||||||
else:
|
else:
|
||||||
print("ASIO API not found, using system default device.")
|
print("ASIO API not found, using system default device.")
|
||||||
|
|
||||||
@@ -740,21 +739,5 @@ class ASIOEngine:
|
|||||||
return self.music_streams[music].get_time_played()
|
return self.music_streams[music].get_time_played()
|
||||||
raise ValueError(f"Music stream {music} not initialized")
|
raise ValueError(f"Music stream {music} not initialized")
|
||||||
|
|
||||||
class AudioEngineWrapper:
|
audio = AudioEngine(get_config()["audio"]["device_type"])
|
||||||
def __init__(self, host_api):
|
audio.set_master_volume(0.75)
|
||||||
self.host_api = host_api
|
|
||||||
if host_api == 'WASAPI':
|
|
||||||
self._module = ray
|
|
||||||
elif host_api == 'ASIO':
|
|
||||||
self._module = ASIOEngine()
|
|
||||||
else:
|
|
||||||
raise Exception("Invalid host API passed to wrapper")
|
|
||||||
def __getattr__(self, name):
|
|
||||||
try:
|
|
||||||
return getattr(self._module, name)
|
|
||||||
except AttributeError:
|
|
||||||
raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}' and '{type(self._module).__name__}' has no attribute '{name}'")
|
|
||||||
|
|
||||||
audio = AudioEngineWrapper(get_config()["audio"]["device_type"])
|
|
||||||
if get_config()["audio"]["device_type"] == 'ASIO':
|
|
||||||
audio.set_master_volume(0.75)
|
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ class GameScreen:
|
|||||||
self.on_screen_start()
|
self.on_screen_start()
|
||||||
self.current_ms = get_current_ms() - self.start_ms
|
self.current_ms = get_current_ms() - self.start_ms
|
||||||
if (self.current_ms >= self.tja.offset*1000 + self.start_delay) and not self.song_started:
|
if (self.current_ms >= self.tja.offset*1000 + self.start_delay) and not self.song_started:
|
||||||
|
if self.song_music is not None:
|
||||||
if not audio.is_sound_playing(self.song_music):
|
if not audio.is_sound_playing(self.song_music):
|
||||||
audio.play_sound(self.song_music)
|
audio.play_sound(self.song_music)
|
||||||
if self.movie is not None:
|
if self.movie is not None:
|
||||||
@@ -252,6 +253,7 @@ class Player:
|
|||||||
self.gauge_hit_effect: list[GaugeHitEffect] = []
|
self.gauge_hit_effect: list[GaugeHitEffect] = []
|
||||||
|
|
||||||
self.autoplay_hit_side = 'L'
|
self.autoplay_hit_side = 'L'
|
||||||
|
self.last_subdivision = -1
|
||||||
|
|
||||||
def get_result_score(self):
|
def get_result_score(self):
|
||||||
return self.score, self.good_count, self.ok_count, self.bad_count, self.total_drumroll, self.max_combo
|
return self.score, self.good_count, self.ok_count, self.bad_count, self.total_drumroll, self.max_combo
|
||||||
@@ -475,13 +477,32 @@ class Player:
|
|||||||
self.check_note(game_screen, config["note_type"])
|
self.check_note(game_screen, config["note_type"])
|
||||||
self.input_log[game_screen.current_ms] = (hit_type, key)
|
self.input_log[game_screen.current_ms] = (hit_type, key)
|
||||||
|
|
||||||
def autoplay_manager(self, game_screen):
|
def autoplay_manager(self, game_screen: GameScreen):
|
||||||
if not get_config()["general"]["autoplay"]:
|
if not get_config()["general"]["autoplay"]:
|
||||||
return
|
return
|
||||||
if len(self.play_notes) == 0:
|
if len(self.play_notes) == 0:
|
||||||
return
|
return
|
||||||
note = self.play_notes[0]
|
note = self.play_notes[0]
|
||||||
if game_screen.current_ms >= note.hit_ms and note.type != 8:
|
if self.is_drumroll or self.is_balloon:
|
||||||
|
subdivision_in_ms = game_screen.current_ms // ((60000 * 4 / game_screen.tja.bpm) / 24)
|
||||||
|
if subdivision_in_ms > self.last_subdivision:
|
||||||
|
self.last_subdivision = subdivision_in_ms
|
||||||
|
hit_type = 'DON'
|
||||||
|
self.lane_hit_effect = LaneHitEffect(hit_type)
|
||||||
|
if self.autoplay_hit_side == 'L':
|
||||||
|
self.autoplay_hit_side = 'R'
|
||||||
|
else:
|
||||||
|
self.autoplay_hit_side = 'L'
|
||||||
|
self.draw_drum_hit_list.append(DrumHitEffect(hit_type, self.autoplay_hit_side))
|
||||||
|
audio.play_sound(game_screen.sound_don)
|
||||||
|
type = note.type
|
||||||
|
if type == 6 or type == 9:
|
||||||
|
type = 3
|
||||||
|
elif type == 5 or type == 7:
|
||||||
|
type = 1
|
||||||
|
self.check_note(game_screen, type)
|
||||||
|
else:
|
||||||
|
while game_screen.current_ms >= note.hit_ms and note.type <= 4:
|
||||||
hit_type = 'DON'
|
hit_type = 'DON'
|
||||||
if note.type == 2 or note.type == 4:
|
if note.type == 2 or note.type == 4:
|
||||||
hit_type = 'KAT'
|
hit_type = 'KAT'
|
||||||
@@ -499,6 +520,11 @@ class Player:
|
|||||||
elif type == 5 or type == 7:
|
elif type == 5 or type == 7:
|
||||||
type = 1
|
type = 1
|
||||||
self.check_note(game_screen, type)
|
self.check_note(game_screen, type)
|
||||||
|
if len(self.play_notes) > 0:
|
||||||
|
note = self.play_notes[0]
|
||||||
|
print(note)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
def update(self, game_screen: GameScreen):
|
def update(self, game_screen: GameScreen):
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user