Git Product home page Git Product logo

Comments (3)

zhanbao2000 avatar zhanbao2000 commented on August 22, 2024

能否提供一下 Aleph-0 的 FTR 谱面?新曲谱面我实在是没有(

from arcaeachartrender.

htxzdfunny avatar htxzdfunny commented on August 22, 2024

能否提供一下 Aleph-0 的 FTR 谱面?新曲谱面我实在是没有(

已发送到您的QQ, 请查收(

from arcaeachartrender.

zhanbao2000 avatar zhanbao2000 commented on August 22, 2024

大概知道原因了,问题核心在于按小节对齐与 BPM 分布。

按小节对齐

ArcaeaChartRender 先绘制一幅连续的纵向谱面,然后按照大约 10 秒一段分割该纵向谱面,并横向拼接。这一分割拼接操作在 Render._post_processing_segment() 过程中实现

这个所谓 “合适的间隔” 并不严格等于 10 秒,而是根据实际谱面的主 BPM 来计算,从而使分割时能够按照小节对齐。

所谓主 BPM,是指在 aff 文件中持续时间总和最长的 BPM 数值。不使用 songlist 中定义的 bpm_base 的原因是,有些谱面尤其是自制谱的 bpm_base 就是图一乐乱写的,这样会造成渲染出来的几乎整张图都标记成了变速区域,也让按小节对齐这一操作没有了意义。

bpm_proportion = self._chart.get_bpm_proportion()
main_bar_duration = 4 * 60000 / max(bpm_proportion, key=bpm_proportion.get)
segment = int(self._chart.end_time / 10000)
segment_duration = (self._chart.end_time / segment // main_bar_duration or 1) * main_bar_duration
segment_count = ceil(self._chart.end_time / segment_duration)

上述代码在 L353 中脚本计算出精确的 10 秒间隔,在 L354 中脚本试图按照主 BPM 微调间隔时间,从而在稍后分割时可以按照小节对齐。

BPM 分布

ArcaeaChartRender 通过 Chart.get_bpm_proportion() 方法计算 aff 文件的 BPM 分布,从而计算出主 BPM。

我通过以下方式计算 2.aff1.aff 的 BPM 分布

from ArcaeaChartRender.aff.decoder import parse_aff
from ArcaeaChartRender.utils import read_file

chart = parse_aff(read_file(r'F:\main_temp\issue\2.aff'))
for bpm, prop in sorted(chart.get_bpm_proportion().items(), key=lambda x: x[1], reverse=True):
    print(bpm, '\t', prop)

2.aff :

250.0 	 0.29666666666666663
0.0 	 0.2668
35.0 	 0.07618888888888889
0.01 	 0.06474444444444445
125.0 	 0.04800000000000001
...

1.aff :

0.01 	 0.3315444444444444
250.0 	 0.294
35.0 	 0.07618888888888889
125.0 	 0.04800000000000001
25.0 	 0.042666666666666665
...

可以看到 1.aff 的主 BPM 为 0.01 而不是 250.0,出现这个问题的原因详见 1.aff 的末尾,一看便知(

如果真的以 0.01 作为这首歌的主 BPM,那么一个小节将会非常漫长(24000000 毫秒),为了按照小节对齐,ArcaeaChartRender 不得不用一个巨大的 box 来分割谱面。

for i in range(segment_count):
box = (
0, Coordinate.from_cartesian(self.h, (i + 1) * segment_height),
width_track + additional_canvas_width, Coordinate.from_cartesian(self.h, i * segment_height)
)
im_cropped = Image.Image.crop(self.im, box)
self.im_tiled_segments.alpha_composite(im_cropped, (i * width_track, 0))

这个巨大的 box 是导致 PIL.Image.DecompressionBombError 异常的原因

from arcaeachartrender.

Related Issues (2)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.