mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 11:40:13 +01:00
idk how to make audio better, this is good enough
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
[general]
|
[general]
|
||||||
fps_counter = false
|
fps_counter = true
|
||||||
judge_offset = 0
|
judge_offset = 0
|
||||||
autoplay = false
|
autoplay = false
|
||||||
sfx = true
|
sfx = true
|
||||||
@@ -15,9 +15,9 @@ right_don = ['J']
|
|||||||
right_kat = ['K']
|
right_kat = ['K']
|
||||||
|
|
||||||
[audio]
|
[audio]
|
||||||
#Options: ASIO, Windows WASAPI
|
|
||||||
device_type = 'Windows WASAPI'
|
device_type = 'Windows WASAPI'
|
||||||
buffer_size = 6
|
buffer_size = 22
|
||||||
|
exclusive = false
|
||||||
|
|
||||||
[video]
|
[video]
|
||||||
screen_width = 1280
|
screen_width = 1280
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import sounddevice as sd
|
|||||||
from pydub import AudioSegment
|
from pydub import AudioSegment
|
||||||
from scipy import signal
|
from scipy import signal
|
||||||
|
|
||||||
from libs.utils import get_config
|
from libs.utils import get_config, rounded
|
||||||
|
|
||||||
|
|
||||||
def resample(data, orig_sr, target_sr):
|
def resample(data, orig_sr, target_sr):
|
||||||
@@ -72,7 +72,7 @@ def get_np_array(sample_width, raw_data):
|
|||||||
raise ValueError(f"Unsupported sample width: {sample_width}")
|
raise ValueError(f"Unsupported sample width: {sample_width}")
|
||||||
|
|
||||||
class Sound:
|
class Sound:
|
||||||
def __init__(self, file_path, data=None, target_sample_rate=48000):
|
def __init__(self, file_path, data=None, target_sample_rate=44100):
|
||||||
self.file_path = file_path
|
self.file_path = file_path
|
||||||
self.data = data
|
self.data = data
|
||||||
self.channels = 0
|
self.channels = 0
|
||||||
@@ -187,7 +187,7 @@ class Sound:
|
|||||||
return output
|
return output
|
||||||
|
|
||||||
class Music:
|
class Music:
|
||||||
def __init__(self, file_path, data=None, file_type=None, target_sample_rate=48000):
|
def __init__(self, file_path, data=None, file_type=None, target_sample_rate=44100):
|
||||||
self.file_path = file_path
|
self.file_path = file_path
|
||||||
self.file_type = file_type
|
self.file_type = file_type
|
||||||
self.data = data
|
self.data = data
|
||||||
@@ -414,8 +414,8 @@ class Music:
|
|||||||
|
|
||||||
class AudioEngine:
|
class AudioEngine:
|
||||||
def __init__(self, type: str):
|
def __init__(self, type: str):
|
||||||
self.target_sample_rate = 48000
|
self.target_sample_rate = 44100
|
||||||
self.buffer_size = get_config()["audio"]["buffer_size"]
|
self.buffer_size = 10
|
||||||
self.sounds = {}
|
self.sounds = {}
|
||||||
self.music_streams = {}
|
self.music_streams = {}
|
||||||
self.stream = None
|
self.stream = None
|
||||||
@@ -442,7 +442,6 @@ class AudioEngine:
|
|||||||
asio_api_index = i
|
asio_api_index = i
|
||||||
break
|
break
|
||||||
|
|
||||||
print(hostapis)
|
|
||||||
if isinstance(hostapis, tuple):
|
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:
|
||||||
@@ -455,6 +454,13 @@ class AudioEngine:
|
|||||||
if isinstance(device_info, sd.DeviceList):
|
if isinstance(device_info, sd.DeviceList):
|
||||||
raise Exception("Invalid ASIO Device")
|
raise Exception("Invalid ASIO Device")
|
||||||
print(f"Using default ASIO device: {device_info['name']}")
|
print(f"Using default ASIO device: {device_info['name']}")
|
||||||
|
print(device_info)
|
||||||
|
self.buffer_size = rounded(device_info['default_low_output_latency']*1000)
|
||||||
|
if 'buffer_size' in get_config()['audio']:
|
||||||
|
self.buffer_size = get_config()['audio']['buffer_size']
|
||||||
|
self.target_sample_rate = device_info['default_samplerate']
|
||||||
|
if 'sample_rate' in get_config()['audio']:
|
||||||
|
self.target_sample_rate = get_config()['audio']['sample_rate']
|
||||||
# Set output channels based on device capabilities
|
# Set output channels based on device capabilities
|
||||||
self.output_channels = device_info['max_output_channels']
|
self.output_channels = device_info['max_output_channels']
|
||||||
if self.output_channels > 2:
|
if self.output_channels > 2:
|
||||||
@@ -587,16 +593,21 @@ class AudioEngine:
|
|||||||
self._initialize_asio()
|
self._initialize_asio()
|
||||||
|
|
||||||
# Set up and start the stream
|
# Set up and start the stream
|
||||||
|
extra_settings = None
|
||||||
|
buffer_size = self.buffer_size
|
||||||
self.stream = sd.OutputStream(
|
self.stream = sd.OutputStream(
|
||||||
samplerate=self.target_sample_rate,
|
samplerate=self.target_sample_rate,
|
||||||
channels=self.output_channels,
|
channels=self.output_channels,
|
||||||
callback=self._audio_callback,
|
callback=self._audio_callback,
|
||||||
blocksize=self.buffer_size,
|
blocksize=buffer_size,
|
||||||
device=self.device_id
|
device=self.device_id,
|
||||||
|
latency='low',
|
||||||
|
extra_settings=extra_settings
|
||||||
)
|
)
|
||||||
self.stream.start()
|
self.stream.start()
|
||||||
self.running = True
|
self.running = True
|
||||||
self.audio_device_ready = True
|
self.audio_device_ready = True
|
||||||
|
print(self.stream.samplerate, self.stream.blocksize, self.stream.latency*1000)
|
||||||
|
|
||||||
# Start update thread for music streams
|
# Start update thread for music streams
|
||||||
self._start_update_thread()
|
self._start_update_thread()
|
||||||
@@ -634,7 +645,7 @@ class AudioEngine:
|
|||||||
|
|
||||||
def load_sound(self, fileName: str) -> str | None:
|
def load_sound(self, fileName: str) -> str | None:
|
||||||
try:
|
try:
|
||||||
sound = Sound(fileName, self.target_sample_rate)
|
sound = Sound(fileName, target_sample_rate=self.target_sample_rate)
|
||||||
sound_id = f"sound_{len(self.sounds)}"
|
sound_id = f"sound_{len(self.sounds)}"
|
||||||
self.sounds[sound_id] = sound
|
self.sounds[sound_id] = sound
|
||||||
print(f"Loaded sound from {fileName} as {sound_id}")
|
print(f"Loaded sound from {fileName} as {sound_id}")
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ class GameScreen:
|
|||||||
self.tja.distance = self.width - self.judge_x
|
self.tja.distance = self.width - self.judge_x
|
||||||
session_data.song_title = self.tja.title
|
session_data.song_title = self.tja.title
|
||||||
|
|
||||||
self.player_1 = Player(self, 1, difficulty, metadata, get_config()["general"]["judge_offset"])
|
self.player_1 = Player(self, 1, difficulty, metadata)
|
||||||
self.song_music = audio.load_sound(str(Path(self.tja.wave)))
|
self.song_music = audio.load_sound(str(Path(self.tja.wave)))
|
||||||
self.start_ms = (get_current_ms() - self.tja.offset*1000)
|
self.start_ms = (get_current_ms() - self.tja.offset*1000)
|
||||||
|
|
||||||
@@ -132,6 +132,7 @@ class GameScreen:
|
|||||||
ray.unload_texture(texture)
|
ray.unload_texture(texture)
|
||||||
self.song_started = False
|
self.song_started = False
|
||||||
self.end_ms = 0
|
self.end_ms = 0
|
||||||
|
self.movie = None
|
||||||
return 'RESULT'
|
return 'RESULT'
|
||||||
|
|
||||||
def write_score(self):
|
def write_score(self):
|
||||||
@@ -159,7 +160,7 @@ class GameScreen:
|
|||||||
def update(self):
|
def update(self):
|
||||||
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 - get_config()["general"]["judge_offset"]) and not self.song_started:
|
||||||
if self.song_music is not None:
|
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)
|
||||||
@@ -206,7 +207,7 @@ class Player:
|
|||||||
TIMING_OK = 75.0750045776367
|
TIMING_OK = 75.0750045776367
|
||||||
TIMING_BAD = 108.441665649414
|
TIMING_BAD = 108.441665649414
|
||||||
|
|
||||||
def __init__(self, game_screen: GameScreen, player_number: int, difficulty: int, metadata, judge_offset: int):
|
def __init__(self, game_screen: GameScreen, player_number: int, difficulty: int, metadata):
|
||||||
|
|
||||||
self.player_number = player_number
|
self.player_number = player_number
|
||||||
self.difficulty = difficulty
|
self.difficulty = difficulty
|
||||||
@@ -215,8 +216,6 @@ class Player:
|
|||||||
self.total_notes = len([note for note in self.play_notes if 0 < note.type < 5])
|
self.total_notes = len([note for note in self.play_notes if 0 < note.type < 5])
|
||||||
self.base_score = calculate_base_score(self.play_notes)
|
self.base_score = calculate_base_score(self.play_notes)
|
||||||
|
|
||||||
self.judge_offset = judge_offset
|
|
||||||
|
|
||||||
#Note management
|
#Note management
|
||||||
self.current_bars: list[Note] = []
|
self.current_bars: list[Note] = []
|
||||||
self.current_notes_draw: list[Note | Drumroll | Balloon] = []
|
self.current_notes_draw: list[Note | Drumroll | Balloon] = []
|
||||||
@@ -259,7 +258,7 @@ class Player:
|
|||||||
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
|
||||||
|
|
||||||
def get_position(self, game_screen: GameScreen, ms: float, pixels_per_frame: float) -> int:
|
def get_position(self, game_screen: GameScreen, ms: float, pixels_per_frame: float) -> int:
|
||||||
return int(game_screen.width + pixels_per_frame * 60 / 1000 * (ms - game_screen.current_ms + self.judge_offset) - 64)
|
return int(game_screen.width + pixels_per_frame * 60 / 1000 * (ms - game_screen.current_ms) - 64)
|
||||||
|
|
||||||
def animation_manager(self, animation_list: list):
|
def animation_manager(self, animation_list: list):
|
||||||
if len(animation_list) <= 0:
|
if len(animation_list) <= 0:
|
||||||
@@ -420,7 +419,7 @@ class Player:
|
|||||||
if game_screen.current_ms > (curr_note.hit_ms + Player.TIMING_BAD):
|
if game_screen.current_ms > (curr_note.hit_ms + Player.TIMING_BAD):
|
||||||
return
|
return
|
||||||
big = curr_note.type == 3 or curr_note.type == 4
|
big = curr_note.type == 3 or curr_note.type == 4
|
||||||
if (curr_note.hit_ms - Player.TIMING_GOOD) + self.judge_offset <= game_screen.current_ms <= (curr_note.hit_ms + Player.TIMING_GOOD) + self.judge_offset:
|
if (curr_note.hit_ms - Player.TIMING_GOOD) <= game_screen.current_ms <= (curr_note.hit_ms + Player.TIMING_GOOD):
|
||||||
self.draw_judge_list.append(Judgement('GOOD', big))
|
self.draw_judge_list.append(Judgement('GOOD', big))
|
||||||
self.lane_hit_effect = LaneHitEffect('GOOD')
|
self.lane_hit_effect = LaneHitEffect('GOOD')
|
||||||
self.good_count += 1
|
self.good_count += 1
|
||||||
@@ -428,14 +427,14 @@ class Player:
|
|||||||
self.base_score_list.append(ScoreCounterAnimation(self.base_score))
|
self.base_score_list.append(ScoreCounterAnimation(self.base_score))
|
||||||
self.note_correct(game_screen, curr_note)
|
self.note_correct(game_screen, curr_note)
|
||||||
|
|
||||||
elif (curr_note.hit_ms - Player.TIMING_OK) + self.judge_offset <= game_screen.current_ms <= (curr_note.hit_ms + Player.TIMING_OK) + self.judge_offset:
|
elif (curr_note.hit_ms - Player.TIMING_OK) <= game_screen.current_ms <= (curr_note.hit_ms + Player.TIMING_OK):
|
||||||
self.draw_judge_list.append(Judgement('OK', big))
|
self.draw_judge_list.append(Judgement('OK', big))
|
||||||
self.ok_count += 1
|
self.ok_count += 1
|
||||||
self.score += 10 * math.floor(self.base_score / 2 / 10)
|
self.score += 10 * math.floor(self.base_score / 2 / 10)
|
||||||
self.base_score_list.append(ScoreCounterAnimation(10 * math.floor(self.base_score / 2 / 10)))
|
self.base_score_list.append(ScoreCounterAnimation(10 * math.floor(self.base_score / 2 / 10)))
|
||||||
self.note_correct(game_screen, curr_note)
|
self.note_correct(game_screen, curr_note)
|
||||||
|
|
||||||
elif (curr_note.hit_ms - Player.TIMING_BAD) + self.judge_offset <= game_screen.current_ms <= (curr_note.hit_ms + Player.TIMING_BAD) + self.judge_offset:
|
elif (curr_note.hit_ms - Player.TIMING_BAD) <= game_screen.current_ms <= (curr_note.hit_ms + Player.TIMING_BAD):
|
||||||
self.draw_judge_list.append(Judgement('BAD', big))
|
self.draw_judge_list.append(Judgement('BAD', big))
|
||||||
self.bad_count += 1
|
self.bad_count += 1
|
||||||
self.combo = 0
|
self.combo = 0
|
||||||
|
|||||||
Reference in New Issue
Block a user