File size: 3,365 Bytes
bd05f58
 
 
a6cd87b
 
 
bd05f58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
from pydub import AudioSegment
import numpy as np

DON_WAV = "./Arcade - Taiko no Tatsujin 2020 Version - Common Sound Effects/Don.wav"
KATSU_WAV = "./Arcade - Taiko no Tatsujin 2020 Version - Common Sound Effects/Katsu.wav"
BALLOON_BANG_WAV = "./Arcade - Taiko no Tatsujin 2020 Version - Common Sound Effects/Balloon.wav"

COURSE = [
    {
        "audio": AudioSegment.empty(),
        "label": "かんたん/梅花(簡單)/Easy",
    },
    {
        "audio": AudioSegment.empty(),
        "label": "ふつう/竹子(普通)/Normal",
    },
    {
        "audio": AudioSegment.empty(),
        "label": "むずかしい/樹(困難)/Hard",
    },
    {
        "audio": AudioSegment.empty(),
        "label": "おに/魔王/Oni",
    },
    {
        "audio": AudioSegment.empty(),
        "label": "裏/Edit",
    }
]

HIT_PER_SEC = 30

def preprocess(data:list, offset:float=0):
    chart = []
    for m in data:
        if m[0] in {1, 3}:  # Don or Big Don
            chart.append((DON_WAV, offset + m[1]))
        elif m[0] in {2, 4}:  # Katsu or Big Katsu
            chart.append((KATSU_WAV, offset + m[1]))
        elif m[0] in {5, 6}:  # Drum Roll or Big Drum Roll
            count = m[1]
            while count < m[2]:
                chart.append((DON_WAV, offset + count))
                count += (1 / HIT_PER_SEC)
                
        elif m[0] == 7:  # Balloon
            count = m[1]
            balloon_count = 0
            while count < m[2] and balloon_count < m[3]:
                chart.append((DON_WAV, offset + count))
                count += (1 / HIT_PER_SEC)
                balloon_count += 1

            if balloon_count >= m[3]:
                chart.append((BALLOON_BANG_WAV, offset + m[1]))
        else:
            raise ValueError("Your json file has some problems.")
    
    return chart

def resize_audio(file_path:str, target_duration:int, target_amplitude:int):
    audio = AudioSegment.from_wav(file_path)
    
    audio = audio[:target_duration * 1000]

    if file_path == DON_WAV or file_path == BALLOON_BANG_WAV:
        return audio

    audio = audio - (audio.dBFS - target_amplitude)
    return audio

def generate_taiko_wav(chart: list, music:str=None):
    max_length = int(max([start_time + len(resize_audio(file_path, target_duration=1, target_amplitude=-20))
                         for file_path, start_time in chart]))

    mixed_audio = np.zeros(max_length)

    for file_path, start_time in chart:
        audio = resize_audio(file_path, target_duration=0.5, target_amplitude=-20)
        audio_array = np.array(audio.get_array_of_samples())

        start_index = int(start_time * audio.frame_rate)
        end_index = start_index + len(audio_array)

        if len(mixed_audio) < end_index:
            mixed_audio = np.pad(mixed_audio, (0, end_index - len(mixed_audio)))

        mixed_audio[start_index:end_index] += audio_array

    mixed_audio = np.clip(mixed_audio, -32768, 32767)

    mixed_audio_segment = AudioSegment(
        mixed_audio.astype(np.int16).tobytes(),
        frame_rate=audio.frame_rate,
        sample_width=2,
        channels=1
    )

    if music is None:
        return mixed_audio_segment
    else:
        background_music = AudioSegment.from_ogg(music)
        mixed_audio_with_bg = background_music.overlay(mixed_audio_segment)
        return mixed_audio_with_bg