Skip to content

Commit

Permalink
Merge pull request #4 from thomasasfk/tafk-new-songs
Browse files Browse the repository at this point in the history
Change tick logic & add more songs!
  • Loading branch information
thomasasfk committed Sep 30, 2023
2 parents ff14012 + 6f7df5b commit e15c327
Show file tree
Hide file tree
Showing 1,494 changed files with 637,331 additions and 384,222 deletions.
48 changes: 22 additions & 26 deletions drs2dd.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
from model.dancedash import DDLineNode
from model.dancedash import DDRoadBlockNode
from model.dancedash import DDSphereNode
from model.dancedash import DRS2DD_MAP_PREFIX
from model.dancedash import DRS_TO_DDS_LINE_NOTE_TYPE
from model.dancedash import DRS_TO_DDS_NOTE_TYPE
from model.dancedash import ORDER_COUNT_PER_BEAT
from model.dancedash import X_Y
from model.dancerush import ALBUM_NAME
from model.dancerush import DEFAULT_TRACK_DIR
from model.dancerush import DRS_ALBUM_ID
from model.dancerush import DRS_DOWN
from model.dancerush import DRS_JUMP
from model.dancerush import DRSSongData
Expand All @@ -45,15 +45,16 @@ def map_sphere_nodes(
difficulty: DRSSongDifficulty,
total_time_seconds: float,
bps: float,
ticks_per_second: float,
) -> list[DDSphereNode]:
spheres = []
for track_step in difficulty.track.sequence_data:
if track_step.long_point or track_step.is_down_or_up:
continue

if track_step.tick_info.start_tick:
seconds = track_step.tick_info.end_tick / ticks_per_second
if track_step.tick_info.end_tick:
seconds = difficulty.track.info.determine_seconds_of_tick(
track_step.tick_info.end_tick,
)
else:
seconds = track_step.tick_info.stime_ms / 1000

Expand All @@ -72,7 +73,6 @@ def map_line_nodes(
difficulty: DRSSongDifficulty,
total_time_seconds: float,
bps: float,
ticks_per_second: float,
) -> list[DDLineNode]:
lines = []
for line_group_id, track_step in enumerate(difficulty.track.sequence_data, start=1):
Expand All @@ -95,7 +95,9 @@ def map_line_nodes(
index_in_line += 1

if drs_track_point.tick:
seconds = drs_track_point.tick / ticks_per_second
seconds = difficulty.track.info.determine_seconds_of_tick(
drs_track_point.tick,
)
else:
seconds = drs_track_point.point_time / 1000

Expand Down Expand Up @@ -126,15 +128,16 @@ def map_down_and_jump_notes(
difficulty: DRSSongDifficulty,
total_time_seconds: float,
bps: float,
ticks_per_second: float,
) -> list[DDRoadBlockNode]:
road_blocks = []
for track_step in difficulty.track.sequence_data:
if not track_step.is_down_or_up:
continue

if track_step.tick_info.start_tick:
seconds = track_step.tick_info.end_tick / ticks_per_second
if track_step.tick_info.end_tick:
seconds = difficulty.track.info.determine_seconds_of_tick(
track_step.tick_info.end_tick,
)
else:
seconds = track_step.tick_info.stime_ms / 1000

Expand All @@ -161,12 +164,9 @@ def create_dd_tracks_from_DRSSongData(drs_song_data: DRSSongData, target_dir: st
if not target_dir:
target_dir = f'{DEFAULT_TRACK_DIR}/{create_valid_filename(drs_song_data.info.title_name)}/'

highest_bpm = max(
drs_song_data.difficulties.difficulty_1a.track.info.bpm_info, key=lambda x: x.bpm,
).bpm
# note we don't use drs_song_data.info.bpm_max as it is not always correct... sometimes higher bpms exist.
# not sure why.
dd_bpm = int(highest_bpm / 100)
dd_bpm = int(
drs_song_data.difficulties.difficulty_1a.track.info.highest_bpm / 100,
)
dd_bps = dd_bpm / 60

folder_path = TRACK_ID_TO_PATH.get(drs_song_data.song_id)
Expand All @@ -193,20 +193,15 @@ def create_dd_tracks_from_DRSSongData(drs_song_data: DRSSongData, target_dir: st
if attr in ('difficulty_2a', 'difficulty_2b'): # 2 player difficulties
continue

ticks_per_second = None
if difficulty.track.clip and difficulty.track.clip.end_time:
end_time_seconds = difficulty.track.clip.end_time / 1000
ticks_per_second = difficulty.track.info.end_tick / end_time_seconds

song_length_f = float(song_length)
sphere_notes = map_sphere_nodes(
difficulty, song_length_f, dd_bps, ticks_per_second,
difficulty, song_length_f, dd_bps,
)
line_notes = map_line_nodes(
difficulty, song_length_f, dd_bps, ticks_per_second,
difficulty, song_length_f, dd_bps,
)
road_block_notes = map_down_and_jump_notes(
difficulty, song_length_f, dd_bps, ticks_per_second,
difficulty, song_length_f, dd_bps,
)

total_note_count = len(sphere_notes + line_notes + road_block_notes) # noqa
Expand Down Expand Up @@ -237,7 +232,8 @@ def create_dd_tracks_from_DRSSongData(drs_song_data: DRSSongData, target_dir: st
drs_beat_map_info = DDBeatMapInfoFile(
CreateTicks=create_ticks,
CreateTime=str(create_ticks),
BeatMapId=drs_song_data.song_id,
OstId=DRS2DD_MAP_PREFIX,
BeatMapId=DRS2DD_MAP_PREFIX + drs_song_data.song_id,
SongName=drs_song_data.info.title_name,
SongLength=song_length,
SongAuthorName=drs_song_data.info.artist_name,
Expand Down Expand Up @@ -298,8 +294,8 @@ def _process_track(song_id):

album_info = DDAlbumInfo(
OstName='DANCERUSH STARDOM',
BeatMapIdList=[track.BeatMapId for track in tracks],
OstId=DRS_ALBUM_ID,
BeatMapIdList=sorted([track.BeatMapId for track in tracks]),
OstId=DRS2DD_MAP_PREFIX,
CoverPath='DANCERUSH_STARDOM.jpg',
CreateTime=yyyymmdd_to_ticks(datetime.now().strftime('%Y%m%d')),
).save_to_file(DEFAULT_TRACK_DIR)
Expand Down
1 change: 1 addition & 0 deletions fs2dd.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ def create_dd_tracks_from_fs(fs_map_dir: str) -> DDBeatMapInfoFile:

create_ticks = yyyymmdd_to_ticks(datetime.now().strftime('%Y%m%d'))
dd_beat_map_info = DDBeatMapInfoFile(
OstId=random_9_digit_int(),
CreateTicks=create_ticks,
CreateTime=str(create_ticks),
BeatMapId=random_9_digit_int(),
Expand Down
4 changes: 3 additions & 1 deletion model/dancedash.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

ORDER_COUNT_PER_BEAT = 24

DRS2DD_MAP_PREFIX = 44_52_53_000 # 44 = D, 52 = R, 53 = S

DRS_TO_DDS_NOTE_TYPE = {
DRS_LEFT: DD_LEFT,
DRS_RIGHT: DD_RIGHT,
Expand Down Expand Up @@ -157,8 +159,8 @@ class DDBeatMapInfoFile:
SongPath: str
CreateTicks: int
CreateTime: str
OstId: int
EditorVersion: str = '1.3.2'
OstId: int = 0
LevelAuthorName: str = 'https://github.com/thomasasfk/drs2dd'
SongPreviewSection: int = 0
OstName: str | None = None
Expand Down
27 changes: 27 additions & 0 deletions model/dancerush.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
DRS_DOWN = 3
DRS_JUMP = 4

TPS_MULTIPLIER = 0.08 # Multiply this by BPM to get ticks per second

DRS_ALBUM_ID = 2022121400
ALBUM_NAME = f'DANCERUSH STARDOM ({DRS_ALBUM_ID})'
DEFAULT_TRACK_DIR = f'tracks/{ALBUM_NAME}/'
Expand Down Expand Up @@ -170,6 +172,31 @@ class DRSTrackInfo:
bpm_info: list[DRSTrackBPMInfo] = field(default_factory=list)
measure_info: list[DRSTrackMeasureInfo] = field(default_factory=list)

@property
def highest_bpm(self) -> int:
return max(bpm_info.bpm for bpm_info in self.bpm_info)

def determine_seconds_of_tick(self, target_tick: int) -> float:
total_seconds = 0.0
relevant_bpm_infos = sorted(
[b for b in self.bpm_info if b.tick <= target_tick],
key=lambda x: x.tick,
reverse=True,
)

for idx, current_bpm in enumerate(relevant_bpm_infos[:-1]):
next_bpm = relevant_bpm_infos[idx + 1]
tick_range = current_bpm.tick - next_bpm.tick
ticks_per_second = next_bpm.bpm * TPS_MULTIPLIER
seconds_for_range = tick_range / ticks_per_second
total_seconds += seconds_for_range

closest_bpm_info = relevant_bpm_infos[0]
remaining_ticks = target_tick - closest_bpm_info.tick
ticks_per_second = closest_bpm_info.bpm * TPS_MULTIPLIER
total_seconds += remaining_ticks / ticks_per_second
return total_seconds

@classmethod
def from_xml_dict(cls, data: dict):
if type(data['measure_info']['measure']) is list:
Expand Down
51 changes: 47 additions & 4 deletions resources/drs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,54 @@ find . -type f -name "song.json" -exec rm -f {} \;
```

```bash
# Find all M4A audio files in the current directory and its subdirectories, and convert them to ogg format using ffmpeg.
find . -type f -name "*.m4a" -exec sh -c 'ffmpeg -y -i "$1" "${1%.m4a}.ogg"' sh {} \;
# remove 10 seconds from all m4as and convert to ogg files
find . -type f -name "*.m4a" -exec sh -c 'DURATION=$(ffprobe -i "$0" -show_entries format=duration -v quiet -of csv="p=0"); TRIM_TIME=$(awk "BEGIN {print $DURATION - 10}"); ffmpeg -y -ss 0 -t $TRIM_TIME -i "$0" "${0%.m4a}.ogg"' {} \;
```

```bash
# remove 10 seconds from all ogg files
find . -type f -name "*.m4a" -exec sh -c 'DURATION=$(ffprobe -i "$0" -show_entries format=duration -v quiet -of csv="p=0"); TRIM_TIME=$(awk "BEGIN {print $DURATION - 10}"); ffmpeg -ss 0 -t $TRIM_TIME -i "$0" "${0%.m4a}.ogg"' {} \;
#!/bin/bash
find . -type f -name "*.2dx" -exec sh -c '
dir=$(dirname "$0")
filename=$(basename "$0")
file_without_extension="${filename%.*}"
if echo "$filename" | grep -qE "clip|pre"; then
echo "Skipping $filename"
exit 0
fi
cd "$dir" || exit 1
2dxdump "$filename"
ffmpeg -y -i "0.wav" "${file_without_extension}clip1.ogg"
' {} \;
```

```bash
find . -type f -name "1.wav" -exec rm -f {} \;
```

```bash
#!/bin/bash
find . -type f -name "*.s3p" -exec sh -c '
dir=$(dirname "$0")
filename=$(basename "$0")
file_without_extension="${filename%.*}"
output_file="${file_without_extension}clip1.ogg"
if echo "$filename" | grep -qE "clip|pre"; then
echo "Skipping $filename"
exit 0
fi
cd "$dir" || exit 1
if [ -f "$output_file" ]; then
echo "Skipping as $output_file already exists."
exit 0
fi
# uhh yea deal with it lol
../../../../../.venv/Scripts/python ../../../../../s3p_unpack.py --input "$filename"
ffmpeg -y -i "0.wma" "$output_file"
' {} \;
```
2 changes: 1 addition & 1 deletion resources/drs/datax/music/00298/songs.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
{
"song_id": 298,
"difficulties": {
"difficulty_1a": {
Expand Down
44 changes: 44 additions & 0 deletions s3p_unpack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from __future__ import annotations

import argparse
import os
import struct


def get_s3v0_header(file):
header = {}
magic = file.read(4)
if magic != b'S3V0':
raise ValueError('Invalid S3V0 magic')

header['size'], header['original_size'], header['data_hash'] = struct.unpack(
'<III', file.read(12),
)
file.read(16) # skip 16 bytes
return header


if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--input', help='Input S3P file', required=True)
args = parser.parse_args()

with open(args.input, 'rb') as infile:
magic = infile.read(4)
if magic != b'S3P0':
raise ValueError('Invalid S3P0 magic')

num_files = struct.unpack('<I', infile.read(4))[0]
index = []

for i in range(num_files):
offset, size = struct.unpack('<II', infile.read(8))
index.append((offset, size))

for i, (offset, size) in enumerate(index):
infile.seek(offset, 0)
header = get_s3v0_header(infile)
data = infile.read(header['original_size'])
output_file = os.path.join(f'{i}.wma')
with open(output_file, 'wb') as outfile:
outfile.write(data)
Loading

0 comments on commit e15c327

Please sign in to comment.