菜鸟教程小白 发表于 2022-12-11 20:45:02

ios - 使用 AKSampleDescriptor


                                            <p><p><strong>使用 AKSamplerDescriptor</strong></p>

<p>我正在使用一个改编的 AKSampler 示例,在该示例中我尝试使用 Fluid.sf3 melodicSounds 的 sforzando 输出。 Sforzando 为每个乐器创建 .sfz 文件,但所有文件都将全局样本指向一个巨大的 .wav 文件。</p>

<p>在所有的instrument.sfz 文件中,对于要使用的波形文件部分,都有一个偏移量和端点描述。 </p>

<p>当我加载 .sfz 文件时,由于内存问题,我遇到了崩溃。似乎对于 .sfz 文件中的每个已定义区域,都会再次加载完整的 .wav 文件 (140 mB)。 </p>

<p>最有可能的是,在重新加载完整的 .wav 文件时,如 AKSampler 示例中所做的那样使用 AKSampleDescriptor 加载示例文件将忽略偏移量和端点(AKSampleDescriptor.startPoint 和 AKSampleDescriptor.endPoint)。</p>

<p>有没有办法从样本文件中从头到尾加载所需的部分,因为完整的文件包含所有乐器的所有样本数据(我知道并使用当时只提取一种乐器的复音并且工作正常,但这是用于其他用途)</p>

<p>或者,这对我来说似乎是最好的,只需加载一次文件,然后让 sampledescriptors 指向内存中的数据</p></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>很好的建议,Rob。我自己也遇到了这个巨大的 WAV 问题,以前从未见过。我也在使用 Sforzando 进行转换。我将考虑向 AKSampler 添加必要的功能。同时,编写一个程序将一个 WAV 文件切割成更小的部分并相应地调整 SFZ 可能会更容易。</p>

<p>这里有一些 Python 2.7 代码来执行此操作,我已成功地将其与 Sforzando 转换的 sf2 soundfont 一起使用。它可能需要更改才能为您工作——sfz 文件之间存在巨大差异——但至少它可能会帮助您入门。此代码需要 <a href="http://pydub.com/" rel="noreferrer noopener nofollow">PyDub</a>用于处理 WAV 音频的库。</p>

<pre><code>import os
import re
from pydub import AudioSegment

def stripComments(text):
    def replacer(match):
      s = match.group(0)
      if s.startswith(&#39;/&#39;):
            return &#34; &#34; # note: a space and not an empty string
      else:
            return s
    pattern = re.compile(
      r&#39;//.*?$|/\*.*?\*/|\&#39;(?:\\.|[^\\\&#39;])*\&#39;|&#34;(?:\\.|[^\\&#34;])*&#34;&#39;,
      re.DOTALL | re.MULTILINE
    )
    return re.sub(pattern, replacer, text)

def updateSplitList(splitList, regionLabels, values):
    if len(values) &gt; 3:
      start = int(values[&#39;offset&#39;])
      length = int(values[&#39;end&#39;]) - start
      name = regionLabels.pop(0)
      splitList.add((name, start, length))

def lookupSplitName(splitList, offset, end):
    for (name, start, end) in splitList:
      if offset == start and end == end:
            return name
    return None

def outputGroupAndRegion(outputFile, splitList, values):
    if values.has_key(&#39;lokey&#39;) and values.has_key(&#39;hikey&#39;) and values.has_key(&#39;pitch_keycenter&#39;):
      outputFile.write(&#39;&lt;group&gt; lokey=%s hikey=%s pitch_keycenter=%s\n&#39; % (values[&#39;lokey&#39;], values[&#39;hikey&#39;], values[&#39;pitch_keycenter&#39;]))
    elif values.has_key(&#39;key&#39;) and values.has_key(&#39;pitch_keycenter&#39;):
      outputFile.write(&#39;&lt;group&gt; key=%s pitch_keycenter=%s\n&#39; % (values[&#39;key&#39;], values[&#39;pitch_keycenter&#39;]))
    if len(values) &gt; 3:
      outputFile.write(&#39;    &lt;region&gt; &#39;)
      if values.has_key(&#39;lovel&#39;) and values.has_key(&#39;hivel&#39;):
            outputFile.write(&#39;lovel=%s hivel=%s &#39; % (values[&#39;lovel&#39;], values[&#39;hivel&#39;]))
      if values.has_key(&#39;tune&#39;):
            outputFile.write(&#39;tune=%s &#39; % values[&#39;tune&#39;])
      if values.has_key(&#39;volume&#39;):
            outputFile.write(&#39;volume=%s &#39; % values[&#39;volume&#39;])
      if values.has_key(&#39;offset&#39;):
            outputFile.write(&#39;offset=0 &#39;)
      if values.has_key(&#39;end&#39;):
            outputFile.write(&#39;end=%d &#39; % (int(values[&#39;end&#39;]) - int(values[&#39;offset&#39;])))
      if values.has_key(&#39;loop_mode&#39;):
            outputFile.write(&#39;loop_mode=%s &#39; % values[&#39;loop_mode&#39;])
      if values.has_key(&#39;loop_start&#39;):
            outputFile.write(&#39;loop_start=%d &#39; % (int(values[&#39;loop_start&#39;]) - int(values[&#39;offset&#39;])))
      if values.has_key(&#39;loop_end&#39;):
            outputFile.write(&#39;loop_end=%d &#39; % (int(values[&#39;loop_end&#39;]) - int(values[&#39;offset&#39;])))
      outputFile.write(&#39;sample=samples/%s&#39; % lookupSplitName(splitList, int(values[&#39;offset&#39;]), int(values[&#39;end&#39;])) + &#39;.wav\n&#39;)

def process(inputFile, outputFile):

    # create a list of region labels
    regionLabels = list()
    for line in open(inputFile):
      if line.strip().startswith(&#39;region_label&#39;):
            regionLabels.append(line.strip().split(&#39;=&#39;))

    # read entire input SFZ file
    sfz = open(inputFile).read()

    # strip comments and create a mixed list of &lt;header&gt; tags and key=value pairs
    sfz_list = stripComments(sfz).split()

    inSection = &#34;none&#34;
    default_path = &#34;&#34;
    global_sample = None
    values = dict()
    splitList = set()

    # parse the input SFZ data and build up splitList
    for item in sfz_list:
      if item.startswith(&#39;&lt;&#39;):
            inSection = item
            updateSplitList(splitList, regionLabels, values)
            values.clear()
            continue
      elif item.find(&#39;=&#39;) &lt; 0:
            #print &#39;unknown:&#39;, item
            continue

      key, value = item.split(&#39;=&#39;)
      if inSection == &#39;&lt;control&gt;&#39; and key == &#39;default_path&#39;:
            default_path = value.replace(&#39;\\&#39;, &#39;/&#39;)
      elif inSection == &#39;&lt;global&gt;&#39; and key == &#39;sample&#39;:
            global_sample = value.replace(&#39;\\&#39;, &#39;/&#39;)
      elif inSection == &#39;&lt;region&gt;&#39;:
            values = value

    # split the wav file
    bigWav = AudioSegment.from_wav(global_sample)
    #print &#34;%d channels, %d bytes/sample, %d frames/sec&#34; % (bigWav.channels, bigWav.sample_width, bigWav.frame_rate)
    frate = float(bigWav.frame_rate)
    for (name, start, length) in splitList:
      startMs = 1000 * start / frate
      endMs = 1000 * (start + length) / frate
      wav = bigWav
      wavName = &#39;samples/&#39; + name + &#39;.wav&#39;
      wav.export(wavName, format=&#39;wav&#39;)

    # parse the input SFZ data again and generate the output SFZ
    for item in sfz_list:
      if item.startswith(&#39;&lt;&#39;):
            inSection = item
            outputGroupAndRegion(outputFile, splitList, values)
            values.clear()
            continue
      elif item.find(&#39;=&#39;) &lt; 0:
            #print &#39;unknown:&#39;, item
            continue

      key, value = item.split(&#39;=&#39;)
      if inSection == &#39;&lt;control&gt;&#39; and key == &#39;default_path&#39;:
            default_path = value.replace(&#39;\\&#39;, &#39;/&#39;)
      elif inSection == &#39;&lt;global&gt;&#39; and key == &#39;sample&#39;:
            global_sample = value.replace(&#39;\\&#39;, &#39;/&#39;)
      elif inSection == &#39;&lt;region&gt;&#39;:
            values = value


dirPath = &#39;000&#39;
fileNameList = os.listdir(dirPath)
for fileName in fileNameList:
    if fileName.endswith(&#39;.sfz&#39;):
      inputFile = os.path.join(dirPath, fileName)
      outputFile = open(fileName, &#39;w&#39;)
      print fileName
      process(inputFile, outputFile)
</code></pre></p>
                                   
                                                <p style="font-size: 20px;">关于ios - 使用 AKSampleDescriptor,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/53023548/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/53023548/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - 使用 AKSampleDescriptor