在上一篇文章中,我介绍了如何从 MOD 文件中提取原始样本数据以及如何播放它。下一步是将歌曲数据从 MOD 文件中取出并放入更有用的数据结构中。
根据我找到的来源(见上一篇文章),歌曲数据以每个“模式”1024 字节存储。模式是 4 个通道中 64 个音符的序列,每个音符是一个小节的 1/16。原始 MOD 文件包含四个通道,这意味着总共可以同时播放四个样本或乐器。每个音符是 4 个字节,每行包含 4 个音符,每个模式包含 64 行,每个模式有 1024 个字节。
对于每个音符,存储乐器索引、周期(稍后解释)和效果(稍后解释) 。乐器索引存储在字节0的前4位和字节2的前4位。周期存储在字节0的后4位和字节1的所有8位。效果存储在字节0的后4位字节 2 的位和字节 3 的所有 8 位。使用这些信息,我可以编写三个新类来存储歌曲数据,Pattern, Row, 和Note。
<span style="color:#171717"><span style="background-color:#ffffff"><span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">class</span> <span style="color:var(--syntax-name-color)">Note</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">constructor</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">noteData</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">noteData</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">&</span> <span style="color:var(--syntax-literal-color)">0xf0</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">noteData</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">>></span> <span style="color:var(--syntax-literal-color)">4</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">period</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">noteData</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">&</span> <span style="color:var(--syntax-literal-color)">0x0f</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-literal-color)">256</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-name-color)">noteData</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">effect</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">noteData</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">&</span> <span style="color:var(--syntax-literal-color)">0x0f</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-literal-color)">256</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-name-color)">noteData</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">3</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">class</span> <span style="color:var(--syntax-name-color)">Row</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">constructor</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">rowData</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">notes</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">[];</span>
<span style="color:var(--syntax-comment-color)">// Each note is 4 bytes</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">i</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-name-color)">i</span> <span style="color:var(--syntax-error-color)"><</span> <span style="color:var(--syntax-literal-color)">16</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-name-color)">i</span> <span style="color:var(--syntax-error-color)">+=</span> <span style="color:var(--syntax-literal-color)">4</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">noteData</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">rowData</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">slice</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">i</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">i</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-literal-color)">4</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">notes</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">push</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">new</span> <span style="color:var(--syntax-name-color)">Note</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">noteData</span><span style="color:var(--syntax-text-color)">));</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">class</span> <span style="color:var(--syntax-name-color)">Pattern</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">constructor</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">modfile</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">index</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Each pattern is 1024 bytes long</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">data</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">new</span> <span style="color:var(--syntax-text-color)">Uint8Array</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">modfile</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">1084</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-name-color)">index</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-literal-color)">1024</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">1024</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">rows</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">[];</span>
<span style="color:var(--syntax-comment-color)">// Each pattern is made up of 64 rows</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">i</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-name-color)">i</span> <span style="color:var(--syntax-error-color)"><</span> <span style="color:var(--syntax-literal-color)">64</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-error-color)">++</span><span style="color:var(--syntax-name-color)">i</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">rowData</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">slice</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">i</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-literal-color)">16</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">i</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-literal-color)">16</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-literal-color)">16</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">rows</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">push</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">new</span> <span style="color:var(--syntax-name-color)">Row</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">rowData</span><span style="color:var(--syntax-text-color)">));</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span></span></span>
Mod还必须更新类的构造函数以通过Pattern为每个模式调用构造函数来读取歌曲数据。
<span style="color:#171717"><span style="background-color:#ffffff"><span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">class</span> <span style="color:var(--syntax-name-color)">Mod</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">constructor</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">modfile</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// Store the pattern table</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">patternTable</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">new</span> <span style="color:var(--syntax-text-color)">Uint8Array</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">modfile</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">952</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">128</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-comment-color)">// Find the highest pattern number</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">maxPatternIndex</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Math</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">max</span><span style="color:var(--syntax-text-color)">(...</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">patternTable</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-comment-color)">// Extract all instruments</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instruments</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">[];</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">sampleStart</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">1084</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">maxPatternIndex</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-literal-color)">1024</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">i</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-name-color)">i</span> <span style="color:var(--syntax-error-color)"><</span> <span style="color:var(--syntax-literal-color)">31</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-error-color)">++</span><span style="color:var(--syntax-name-color)">i</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">instr</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">new</span> <span style="color:var(--syntax-name-color)">Instrument</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">modfile</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">i</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">sampleStart</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instruments</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">push</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">instr</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-name-color)">sampleStart</span> <span style="color:var(--syntax-error-color)">+=</span> <span style="color:var(--syntax-name-color)">instr</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">length</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-comment-color)">// Extract the pattern data</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">patterns</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">[];</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">i</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-name-color)">i</span> <span style="color:var(--syntax-error-color)"><=</span> <span style="color:var(--syntax-name-color)">maxPatternIndex</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-error-color)">++</span><span style="color:var(--syntax-name-color)">i</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">pattern</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">new</span> <span style="color:var(--syntax-name-color)">Pattern</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">modfile</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">i</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">patterns</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">push</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">pattern</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span></span></span>
播放一种模式的一种通道
现在歌曲数据以更有用的格式存储,是时候播放它了。第一步是播放一种模式的一个通道。回放由process工作集处理器类的方法驱动。对于播放的每个样本,时间向前移动 1/48 000 或 1/44 100 秒,具体取决于音频上下文的采样率。因此,我们可以将样本用作时间源,并根据样本的进展进行所有时间计算。
值得注意的是Amiga Paula 协处理器period的时钟脉冲数,它以主 CPU 时钟速度的一半运行。在 PAL Amiga 上,主 CPU 时钟频率为 7 093 789.2 Hz,因此协处理器频率为 3 546 894.6 Hz。使用周期 214 (音符 C-3 的周期)演奏的样本将以 3 546 894.6/214 = 16 574.3 Hz 播放。对于采样率为 48 000 Hz 的音频上下文,这意味着在输出下一个样本之前,每个样本将输出 48 000/16 574.3 = 2.896 次。每次周期变化时都必须进行这些计算。
要在歌曲中前进,我还需要跟踪歌曲中的当前位置、要播放的当前行以及在移动到下一行之前还剩下多少样本要播放。目前,每行的样本数是使用 125 的 BPM 和音频上下文的采样率计算的。
<span style="color:#171717"><span style="background-color:#ffffff"><span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">PAULA_FREQUENCY</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">3546894.6</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">class</span> <span style="color:var(--syntax-name-color)">PlayerWorklet</span> <span style="color:var(--syntax-declaration-color)">extends</span> <span style="color:var(--syntax-name-color)">AudioWorkletProcessor</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">constructor</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">super</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">port</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">onmessage</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">onmessage</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">bind</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">mod</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">null</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">onmessage</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">e</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">e</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">type</span> <span style="color:var(--syntax-error-color)">===</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">play</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">mod</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">e</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">mod</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleRate</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">e</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleRate</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">bpm</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">125</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">outputsPerRow</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleRate</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-literal-color)">60</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">bpm</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-literal-color)">4</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-comment-color)">// Start at the last row of the pattern "before the first pattern"</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">position</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">rowIndex</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">63</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-comment-color)">// Immediately move to the first row of the first pattern</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">outputsUntilNextRow</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">null</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">period</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">null</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">nextRow</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-error-color)">++</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">rowIndex</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">rowIndex</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-literal-color)">64</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">rowIndex</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-error-color)">++</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">position</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">patternIndex</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">mod</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">patternTable</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">position</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">pattern</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">mod</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">patterns</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">patternIndex</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">row</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">pattern</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">rows</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">rowIndex</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">note</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">row</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">notes</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">note</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">mod</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instruments</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">note</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span> <span style="color:var(--syntax-error-color)">-</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleIndex</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">note</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">period</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">period</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">note</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">period</span> <span style="color:var(--syntax-error-color)">-</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">finetune</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">nextOutput</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">mod</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-literal-color)">0.0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">outputsUntilNextRow</span> <span style="color:var(--syntax-error-color)"><=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">nextRow</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">outputsUntilNextRow</span> <span style="color:var(--syntax-error-color)">+=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">outputsPerRow</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">outputsUntilNextRow</span><span style="color:var(--syntax-error-color)">--</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span> <span style="color:var(--syntax-error-color)">||</span> <span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">period</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-literal-color)">0.0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">period</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-literal-color)">0.0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleIndex</span> <span style="color:var(--syntax-error-color)">>=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">bytes</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">length</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-literal-color)">0.0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">sample</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">bytes</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleIndex</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">sampleRate</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">PAULA_FREQUENCY</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">period</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleIndex</span> <span style="color:var(--syntax-error-color)">+=</span> <span style="color:var(--syntax-name-color)">sampleRate</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleRate</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">sample</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-literal-color)">256.0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">process</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">inputs</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">outputs</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">output</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">outputs</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">channel</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">output</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">i</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-name-color)">i</span> <span style="color:var(--syntax-error-color)"><</span> <span style="color:var(--syntax-name-color)">channel</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">length</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-error-color)">++</span><span style="color:var(--syntax-name-color)">i</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">value</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">nextOutput</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-name-color)">channel</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">i</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">value</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-declaration-color)">true</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">registerProcessor</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">player-worklet</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">PlayerWorklet</span><span style="color:var(--syntax-text-color)">);</span>
</code></span></span></span></span>
要最终播放歌曲的第一个频道,我需要将完整的 mod 数据发送到 worklet,而不仅仅是一个乐器。我还需要发送音频上下文的采样率,以便工作集可以正确计算所有时间。以下是对主线程代码的更改:
<span style="color:#171717"><span style="background-color:#ffffff"><span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// Load Elekfunk from api.modarchive.org</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">url</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">https://api.modarchive.org/downloads.php?moduleid=41529</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">mod</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">await</span> <span style="color:var(--syntax-name-color)">loadMod</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">url</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-comment-color)">// Play a sample when the user clicks</span>
<span style="color:var(--syntax-text-color)">window</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">addEventListener</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">click</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-name-color)">audio</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">resume</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-name-color)">player</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">port</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">postMessage</span><span style="color:var(--syntax-text-color)">({</span>
<span style="color:var(--syntax-name-color)">type</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">play</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-name-color)">mod</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">mod</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-name-color)">sampleRate</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">audio</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleRate</span>
<span style="color:var(--syntax-text-color)">});</span>
<span style="color:var(--syntax-text-color)">});</span>
</code></span></span></span></span>
在这些更改之后,当您单击浏览器窗口时,歌曲的第一个频道开始播放。但是,时机有点不对,有些音符没有正确播放。这是因为尚未实现任何效果。Elekfunk 歌曲使用当前未实现的“Set Speed”效果来加快播放速度,这就是时间错误的原因。此外,要真正欣赏这首歌,需要将所有四个声道混合在一起。我在这篇文章中所做的最后更改是创建一个四通道混音器,并实现“设置速度”效果。
混合多个通道
要将歌曲的四个通道混合在一起,我需要跟踪每个通道的乐器和周期。每个通道都需要有自己的样本索引,并独立于其他通道在样本中向前移动。我创建了一个Channel类来跟踪此信息,并在工作集中创建了该类的四个实例。该nextOutput函数现在遍历所有四个通道,并将每个通道的输出加在一起。为了将输出限制在 -1.0 到 1.0 的范围内,我使用了函数Math.tanh,它是一个双曲正切函数。它有一个很好的属性,即输出始终在 -1.0 和 1.0 之间,并且输出也按比例缩放到输入。
<span style="color:#171717"><span style="background-color:#ffffff"><span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">class</span> <span style="color:var(--syntax-name-color)">Channel</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">constructor</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">worklet</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">worklet</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">worklet</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">null</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">period</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleSpeed</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0.0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleIndex</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">nextOutput</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span> <span style="color:var(--syntax-error-color)">||</span> <span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">period</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-literal-color)">0.0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">sample</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">bytes</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleIndex</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleIndex</span> <span style="color:var(--syntax-error-color)">+=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleSpeed</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleIndex</span> <span style="color:var(--syntax-error-color)">>=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">length</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-literal-color)">0.0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">sample</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-literal-color)">256.0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">play</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">note</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">note</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">worklet</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">mod</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instruments</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">note</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span> <span style="color:var(--syntax-error-color)">-</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleIndex</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">note</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">period</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">period</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">note</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">period</span> <span style="color:var(--syntax-error-color)">-</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">finetune</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">sampleRate</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">PAULA_FREQUENCY</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">period</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleSpeed</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">sampleRate</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">worklet</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleRate</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span></span></span>
<span style="color:#171717"><span style="background-color:#ffffff"><span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">class</span> <span style="color:var(--syntax-name-color)">PlayerWorklet</span> <span style="color:var(--syntax-declaration-color)">extends</span> <span style="color:var(--syntax-name-color)">AudioWorkletProcessor</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">constructor</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">super</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">port</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">onmessage</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">onmessage</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">bind</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">mod</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">null</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">channels</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">[</span> <span style="color:var(--syntax-declaration-color)">new</span> <span style="color:var(--syntax-name-color)">Channel</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">),</span> <span style="color:var(--syntax-declaration-color)">new</span> <span style="color:var(--syntax-name-color)">Channel</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">),</span> <span style="color:var(--syntax-declaration-color)">new</span> <span style="color:var(--syntax-name-color)">Channel</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">),</span> <span style="color:var(--syntax-declaration-color)">new</span> <span style="color:var(--syntax-name-color)">Channel</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">onmessage</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">e</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">e</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">type</span> <span style="color:var(--syntax-error-color)">===</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">play</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">mod</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">e</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">mod</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleRate</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">e</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleRate</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">bpm</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">125</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">outputsPerRow</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleRate</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-literal-color)">60</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">bpm</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-literal-color)">4</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-comment-color)">// Start at the last row of the pattern "before the first pattern"</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">position</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">rowIndex</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">63</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-comment-color)">// Immediately move to the first row of the first pattern</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">outputsUntilNextRow</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">nextRow</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-error-color)">++</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">rowIndex</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">rowIndex</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-literal-color)">64</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">rowIndex</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-error-color)">++</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">position</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">patternIndex</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">mod</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">patternTable</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">position</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">pattern</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">mod</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">patterns</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">patternIndex</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">row</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">pattern</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">rows</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">rowIndex</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">i</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-name-color)">i</span> <span style="color:var(--syntax-error-color)"><</span> <span style="color:var(--syntax-literal-color)">4</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-error-color)">++</span><span style="color:var(--syntax-name-color)">i</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">channels</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">i</span><span style="color:var(--syntax-text-color)">].</span><span style="color:var(--syntax-name-color)">play</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">row</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">notes</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">i</span><span style="color:var(--syntax-text-color)">]);</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">nextOutput</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">mod</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-literal-color)">0.0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">outputsUntilNextRow</span> <span style="color:var(--syntax-error-color)"><=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">outputsUntilNextRow</span> <span style="color:var(--syntax-error-color)"><=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">nextRow</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">outputsUntilNextRow</span><span style="color:var(--syntax-error-color)">--</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">rawOutput</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">channels</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">reduce</span><span style="color:var(--syntax-text-color)">((</span><span style="color:var(--syntax-name-color)">acc</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">channel</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">acc</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-name-color)">channel</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">nextOutput</span><span style="color:var(--syntax-text-color)">(),</span> <span style="color:var(--syntax-literal-color)">0.0</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">Math</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">tanh</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">rawOutput</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">process</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">inputs</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">outputs</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">output</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">outputs</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">channel</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">output</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">i</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-name-color)">i</span> <span style="color:var(--syntax-error-color)"><</span> <span style="color:var(--syntax-name-color)">channel</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">length</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-error-color)">++</span><span style="color:var(--syntax-name-color)">i</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">value</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">nextOutput</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-name-color)">channel</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">i</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">value</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-declaration-color)">true</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span></span></span>
添加第一个效果
我要实现的第一个效果是“设置速度”效果。这种效果可以以两种不同的方式使用。如果该值小于 32,它会设置每行的“刻度”数。如果该值大于或等于 32,则设置每分钟的节拍数。“刻度”是 MOD 格式的一个概念,通常是一行的 1/6。大多数较旧的 MOD 文件从不更改 BPM,而是更改每行的节拍数以加快或减慢歌曲的速度。许多效果根据每行的刻度数执行计算,因此实现此效果很重要。effect我将从向类中添加一个方法开始Channel,我可以使用它来实现所有效果。我还将添加一个setTicksPerRow方法和一个setBpm方法到PlayerWorklet类,我可以用它来更新每行的刻度数。
<span style="color:#171717"><span style="background-color:#ffffff"><span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code> <span style="color:var(--syntax-name-color)">play</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">note</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">note</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">worklet</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">mod</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instruments</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">note</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span> <span style="color:var(--syntax-error-color)">-</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleIndex</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">note</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">period</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">period</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">note</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">period</span> <span style="color:var(--syntax-error-color)">-</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">instrument</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">finetune</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">sampleRate</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">PAULA_FREQUENCY</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">period</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleSpeed</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">sampleRate</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">worklet</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleRate</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">note</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">effect</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">effect</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">note</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">effect</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">effect</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">raw</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">id</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">raw</span> <span style="color:var(--syntax-error-color)">>></span> <span style="color:var(--syntax-literal-color)">8</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">data</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">raw</span> <span style="color:var(--syntax-error-color)">&</span> <span style="color:var(--syntax-literal-color)">0xff</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">id</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-literal-color)">0x0f</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">data</span> <span style="color:var(--syntax-error-color)">>=</span> <span style="color:var(--syntax-literal-color)">1</span> <span style="color:var(--syntax-error-color)">&&</span> <span style="color:var(--syntax-name-color)">data</span> <span style="color:var(--syntax-error-color)"><=</span> <span style="color:var(--syntax-literal-color)">31</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">worklet</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">setTicksPerRow</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">else</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">worklet</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">setBpm</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span></span></span>
<span style="color:#171717"><span style="background-color:#ffffff"><span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code> <span style="color:var(--syntax-name-color)">onmessage</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">e</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">e</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">type</span> <span style="color:var(--syntax-error-color)">===</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">play</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">mod</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">e</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">mod</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleRate</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">e</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleRate</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">setBpm</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">125</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">setTicksPerRow</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">6</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-comment-color)">// Start at the last row of the pattern "before the first pattern"</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">position</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">rowIndex</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">63</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-comment-color)">// Immediately move to the first row of the first pattern</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">outputsUntilNextRow</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">setTicksPerRow</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">ticksPerRow</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">ticksPerRow</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">ticksPerRow</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">outputsPerRow</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleRate</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-literal-color)">60</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">bpm</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-literal-color)">4</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">ticksPerRow</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-literal-color)">6</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">setBpm</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">bpm</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">bpm</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">bpm</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">outputsPerRow</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">sampleRate</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-literal-color)">60</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">bpm</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-literal-color)">4</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">ticksPerRow</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-literal-color)">6</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span></span></span>
结论
通过这些更改,播放器现在可以从 Arte 演示中渲染 Moby 的 Elekfunk 版本,该版本听起来不错。乐器演奏正确,歌曲以正确的速度播放,但仍然缺少很多效果。这些将是本系列接下来几部分的主题。
您可以在atornblad.github.io/js-mod-player尝试此解决方案。
GitHub 存储库中始终提供最新版本的代码。
1801

被折叠的 条评论
为什么被折叠?



