mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 11:40:13 +01:00
add better WASAPI
This commit is contained in:
@@ -101,8 +101,8 @@ def main():
|
||||
ray.toggle_fullscreen()
|
||||
|
||||
next_screen = screen.update()
|
||||
screen.draw()
|
||||
ray.clear_background(ray.BLACK)
|
||||
screen.draw()
|
||||
|
||||
if next_screen is not None:
|
||||
current_screen = next_screen
|
||||
|
||||
@@ -5,7 +5,6 @@ import time
|
||||
import wave
|
||||
from threading import Lock, Thread
|
||||
|
||||
import pyray as ray
|
||||
from numpy import (
|
||||
abs as np_abs,
|
||||
)
|
||||
@@ -413,10 +412,10 @@ class Music:
|
||||
except Exception:
|
||||
raise Exception("unable to close music stream")
|
||||
|
||||
class ASIOEngine:
|
||||
def __init__(self):
|
||||
class AudioEngine:
|
||||
def __init__(self, type: str):
|
||||
self.target_sample_rate = 48000
|
||||
self.buffer_size = get_config()["audio"]["asio_buffer"]
|
||||
self.buffer_size = get_config()["audio"]["buffer_size"]
|
||||
self.sounds = {}
|
||||
self.music_streams = {}
|
||||
self.stream = None
|
||||
@@ -431,6 +430,7 @@ class ASIOEngine:
|
||||
# Threading for music stream updates
|
||||
self.update_thread = None
|
||||
self.update_thread_running = False
|
||||
self.type = type
|
||||
|
||||
def _initialize_asio(self):
|
||||
"""Set up ASIO device"""
|
||||
@@ -438,11 +438,12 @@ class ASIOEngine:
|
||||
hostapis = sd.query_hostapis()
|
||||
asio_api_index = -1
|
||||
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
|
||||
break
|
||||
|
||||
if asio_api_index is not None:
|
||||
print(hostapis)
|
||||
if isinstance(hostapis, tuple):
|
||||
asio_api = hostapis[asio_api_index]
|
||||
if isinstance(asio_api, dict) and 'default_output_device' in asio_api:
|
||||
default_asio_device = asio_api['default_output_device']
|
||||
@@ -461,9 +462,7 @@ class ASIOEngine:
|
||||
self.output_channels = 2
|
||||
return True
|
||||
else:
|
||||
print("No default ASIO device found, using system default.")
|
||||
else:
|
||||
print("ASIO API not found, using system default device.")
|
||||
print("ASIO API not found, using system default device.")
|
||||
|
||||
# If we get here, use default system device
|
||||
self.device_id = None
|
||||
@@ -740,21 +739,5 @@ class ASIOEngine:
|
||||
return self.music_streams[music].get_time_played()
|
||||
raise ValueError(f"Music stream {music} not initialized")
|
||||
|
||||
class AudioEngineWrapper:
|
||||
def __init__(self, host_api):
|
||||
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)
|
||||
audio = AudioEngine(get_config()["audio"]["device_type"])
|
||||
audio.set_master_volume(0.75)
|
||||
|
||||
@@ -160,8 +160,9 @@ class GameScreen:
|
||||
self.on_screen_start()
|
||||
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 not audio.is_sound_playing(self.song_music):
|
||||
audio.play_sound(self.song_music)
|
||||
if self.song_music is not None:
|
||||
if not audio.is_sound_playing(self.song_music):
|
||||
audio.play_sound(self.song_music)
|
||||
if self.movie is not None:
|
||||
self.movie.start(get_current_ms())
|
||||
self.song_started = True
|
||||
@@ -252,6 +253,7 @@ class Player:
|
||||
self.gauge_hit_effect: list[GaugeHitEffect] = []
|
||||
|
||||
self.autoplay_hit_side = 'L'
|
||||
self.last_subdivision = -1
|
||||
|
||||
def get_result_score(self):
|
||||
return self.score, self.good_count, self.ok_count, self.bad_count, self.total_drumroll, self.max_combo
|
||||
@@ -475,30 +477,54 @@ class Player:
|
||||
self.check_note(game_screen, config["note_type"])
|
||||
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"]:
|
||||
return
|
||||
if len(self.play_notes) == 0:
|
||||
return
|
||||
note = self.play_notes[0]
|
||||
if game_screen.current_ms >= note.hit_ms and note.type != 8:
|
||||
hit_type = 'DON'
|
||||
if note.type == 2 or note.type == 4:
|
||||
hit_type = 'KAT'
|
||||
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))
|
||||
sound = game_screen.sound_don if hit_type == "DON" else game_screen.sound_kat
|
||||
audio.play_sound(sound)
|
||||
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)
|
||||
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'
|
||||
if note.type == 2 or note.type == 4:
|
||||
hit_type = 'KAT'
|
||||
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))
|
||||
sound = game_screen.sound_don if hit_type == "DON" else game_screen.sound_kat
|
||||
audio.play_sound(sound)
|
||||
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)
|
||||
if len(self.play_notes) > 0:
|
||||
note = self.play_notes[0]
|
||||
print(note)
|
||||
else:
|
||||
break
|
||||
|
||||
|
||||
def update(self, game_screen: GameScreen):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
import sqlite3
|
||||
from pathlib import Path
|
||||
|
||||
import pyray as ray
|
||||
|
||||
|
||||
Reference in New Issue
Block a user