Spaces:
No application file
No application file
File size: 7,061 Bytes
6755a2d |
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 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
from __future__ import annotations
from typing import TYPE_CHECKING, Dict, List
import numpy as np
from ...data.clip.clip_process import find_idx_by_time, reset_clipseq_id
from ...data.clip.clip_fusion import fuse_clips
from ...utils.util import merge_list_continuous_same_element
if TYPE_CHECKING:
from .music_clip import MusicClip, MusicClipSeq
from .music_map import MusicMap, MusicMapSeq
# TODO: 待和clip操作做整合
def music_clip_is_short(clip: MusicClip, th: float = 3) -> bool:
"""判断音乐片段是否过短
Args:
clip (MusicClip): 待判断的音乐片段
th (float, optional): 短篇的参数. Defaults to 3.
Returns:
bool: 是或不是 短片段
"""
if clip.duration < th:
return False
else:
return True
def music_clip_timepoint_is_target(clip: MusicClip, target: list = [-1, 1, 0]) -> bool:
"""音乐片段的关键点类型是否是目标关键点
关键点类型暂时参考:VideoMashup/videomashup/data_structure/music_data_structure.py
Args:
clip (MusicClip): 待判断的音乐片段
target (list, optional): 目标关键点类别. Defaults to [-1, 1, 0].
Returns:
bool: 是还是不是
"""
timepoint = clip.timepoint_type
if isinstance(timepoint, int):
timepoint = {timepoint}
else:
timepoint = {int(x) for x in timepoint.split("_")}
if timepoint & set(target):
return True
else:
return False
def filter_clipseq_target_point(
clipseq: MusicClipSeq, target: list = [-1, 1, 0]
) -> MusicClipSeq:
"""删除目标关键点之外的点,对相应的片段做融合
Args:
clipseq (MusicClipSeq): 待处理的音乐片段序列
target (list, optional): 保留的目标关键点. Defaults to [-1, 1, 0].
Returns:
MusicClipSeq: 处理后的音乐片段序列
"""
n_clipseq = len(clipseq)
if n_clipseq == 1:
return clipseq
newclipseq = []
start_clip = clipseq[0]
if music_clip_timepoint_is_target(start_clip, target=target):
has_start_clip = True
else:
has_start_clip = False
i = 1
while i <= n_clipseq - 1:
clip = clipseq[i]
start_clip_is_target = music_clip_timepoint_is_target(start_clip, target=target)
next_clip_is_target = music_clip_timepoint_is_target(clip, target=target)
# logger.debug("filter_clipseq_target_point: i={},start={}, clip={}".format(i, start_clip["timepoint_type"], clip["timepoint_type"]))
# logger.debug("start_clip_is_target: {}, next_clip_is_target {}".format(start_clip_is_target, next_clip_is_target))
if not has_start_clip:
start_clip = clip
has_start_clip = next_clip_is_target
else:
if start_clip_is_target:
has_start_clip = True
if next_clip_is_target:
newclipseq.append(start_clip)
start_clip = clip
if i == n_clipseq - 1:
newclipseq.append(clip)
else:
start_clip = fuse_clips(start_clip, clip)
if i == n_clipseq - 1:
newclipseq.append(start_clip)
# logger.debug("filter_clipseq_target_point: fuse {}, {}".format(i, clip["timepoint_type"]))
else:
start_clip = clip
i += 1
newclipseq = reset_clipseq_id(newclipseq)
return newclipseq
def merge_musicclip_into_clipseq(
clip: MusicClipSeq, clipseq: MusicClip, th: float = 1
) -> MusicClipSeq:
"""给clipseq插入一个新的音乐片段,会根据插入后片段是否过短来判断。
Args:
clip (MusicClipSeq): 要插入的音乐片段
clipseq (MusicClip): 待插入的音乐片段序列
th (float, optional): 插入后如果受影响的片段长度过短,则放弃插入. Defaults to 1.
Returns:
MusicClipSeq: _description_
"""
n_clipseq = len(clipseq)
clip_time = clip.time_start
idx = find_idx_by_time(clipseq, clip_time)
last_clip_time_start = clipseq[idx].time_start
next_clip_time_start = clipseq[idx].time_start + clipseq[idx].duration
last_clip_time_delta = clip_time - last_clip_time_start
clip_duration = next_clip_time_start - clip_time
# TODO: 副歌片段改变th参数来提升音符密度,暂不使用,等待音游谱面
# TODO: 待抽离独立的业务逻辑为单独的函数
# 只针对副歌片段插入关键点
if clipseq[idx].text is None or (
clipseq[idx].text is not None
and clipseq[idx].stage is not None
and "C" in clipseq[idx].stage
):
if (last_clip_time_delta > th) and (clip_duration > th):
clip.duration = clip_duration
clipseq[idx].duration = last_clip_time_delta
clipseq.insert(idx + 1, clip)
clipseq = reset_clipseq_id(clipseq)
return clipseq
def merge_music_clipseq(clipseq1: MusicClipSeq, clipseq2: MusicClipSeq) -> MusicClipSeq:
"""将片段序列clipseq2融合到音乐片段序列clipseq1中。融合过程也会判断新片段长度。
Args:
clipseq1 (MusicClipSeq): 要融合的目标音乐片段序列
clipseq2 (MusicClipSeq): 待融合的音乐片段序列
Returns:
MusicClipSeq: 融合后的音乐片段序列
"""
while len(clipseq2) > 0:
clip = clipseq2[0]
clipseq1 = merge_musicclip_into_clipseq(clip, clipseq1)
del clipseq2[0]
return clipseq1
def merge_lyricseq_beatseq(
lyric_clipseq: MusicClipSeq, beat_clipseq: MusicClipSeq
) -> MusicClipSeq:
"""将beat序列融合到歌词序列中
Args:
lyric_clipseq (MusicClipSeq): 歌词序列
beat_clipseq (MusicClipSeq): beat序列
Returns:
MusicClipSeq: 融合后的音乐片段序列
"""
newclipseq = merge_music_clipseq(lyric_clipseq, beat_clipseq)
# for i, clip in enumerate(newclipseq):
# logger.debug("i={}, time_start={}, duration={}".format(i, clip.time_start, clip.duration))
return newclipseq
def get_stageseq_from_clipseq(clipseq: MusicClipSeq) -> List[Dict]:
"""对clip.stage做近邻融合,返回总时间
Returns:
List[Dict]: 根据音乐结构进行分割的片段序列
"""
stages = [clip.stage for clip in clipseq]
merge_stages_idx = merge_list_continuous_same_element(stages)
merge_stages = []
for n, stages_idx in enumerate(merge_stages_idx):
dct = {
"clipid": n,
"time_start": clipseq[stages_idx["start"]].time_start,
"time_end": clipseq[stages_idx["end"]].time_end,
"stage": stages_idx["element"],
"original_clipid": list(
range(stages_idx["start"], stages_idx["end"] + 1)
), # mss都是左闭、 右闭的方式
}
dct["duration"] = dct["time_end"] - dct["time_start"]
merge_stages.append(dct)
return merge_stages
|