sound.md 14 KB


title: Компонент Sound

brief: В этом руководстве объясняется порядок внесения звукового контента в проект Defold, его воспроизведения и управления им.

Компонент Sound

Реализация звука в Defold проста, но мощна. Есть лишь две концепции, о которых необходимо знать:

Компоненты звука : Эти компоненты содержат фактический звуковой контент и обеспечивают средства его воспроизведения.

Звуковые группы : Каждый звуковой компонент может быть отнесен к группе. Группы предлагают простой и интуитивно понятный способ управления звуками, которые должны сочетаться друг с другом. Например, можно создать группу "sound_fx", тогда любой звук, принадлежащий к этой группе, может быть приглушен простым вызовом функции.

Создание звукового компонента

Звуковые компоненты могут быть инстанцированы только на месте в игровом объекте. Создайте новый игровой объект, кликните на нем ПКМ и выберите Add Component ▸ Sound.

Select component

Созданный компонент имеет набор свойств, которые должны быть настроены:

Select component

Sound : Звуковой файл проекта, в формате Wave или Ogg Vorbis. Defold поддерживает звуковые файлы, сохраненные с битовой глубиной 16bit и частотой дискретизации 44100.

Looping : Если опция отмечена, звук будет воспроизводиться Loopcount раз или до явной остановки.

Loopcount : Количество проигрываний зацикленного звука до остановки (0 означает, что звук будет проигрываться до явной остановки).

Group : Имя звуковой группы, к которой должен принадлежать звук. Если оставить это свойство пустым, звук будет назначен встроенной группе "master".

Gain : Задать усиление звука можно непосредственно в компоненте. Это позволяет легко настроить усиление звука, не возвращаясь в звуковую программу и не выполняя повторный экспорт. Подробнее о том, как рассчитывается усиление, см. ниже.

Pan : Задать значение панорамирования для звука можно непосредственно в компоненте. Панорамирование должно быть значением между -1 (-45 градусов влево) и 1 (45 градусов вправо).

Speed : Задать значение скорости звука можно непосредственно в компоненте. Значение 1.0 --- нормальная скорость, 0.5 --- половина скорости и 2.0 --- двойная скорость.

Воспроизведение звука

При правильной настройке компонента Sound можно заставить его воспроизвести звук, вызвав sound.play():

sound.play("go#sound", {delay = 1, gain = 0.5, pan = -1.0, speed = 1.25})

::: sidenote Звук будет продолжать воспроизводиться, даже если игровой объект, к которому принадлежал компонент Sound, будет удален. Можно вызвать sound.stop(), чтобы остановить звук (см. ниже). ::: Каждое сообщение, отправленное компоненту, заставляет его воспроизводить другой экземпляр звука, пока доступный звуковой буфер не будет заполнен и движок не выведет ошибки в консоль. Рекомендуется реализовать какой-либо механизм фильтрации и группировки звуков.

Остановка звука

Если необходимо остановить воспроизведение звука, можно вызвать sound.stop():

sound.stop("go#sound")

Усиление

Gain

Звуковая система имеет 4 уровня усиления:

  • Усиление, установленное для компонента звука.
  • Усиление, установленное при запуске звука через вызов sound.play() или при изменении усиления голоса через вызов sound.set_gain().
  • Усиление, установленное для группы с помощью вызова функции sound.set_group_gain().
  • Усиление, установленное в группе "master". Может быть изменено с помощью sound.set_group_gain(hash("master")).

Выходное усиление является результатом перемножения этих 4 усилений. По умолчанию коэффициент усиления везде равен 1.0 (0 dB).

Звуковые группы

Любой звуковой компонент с указанным именем звуковой группы будет помещен в звуковую группу с этим именем. Если группа не указана, звук будет отнесен к группе "master". Также можно явно задать звуковому компоненту группу "master", что даст тот же эффект.

Имеется несколько функций для получения всех доступных групп, получения строки с именем, получения и установки усиления, среднеквадратичного (RMS, см. http://en.wikipedia.org/wiki/Root_mean_square) и пикового усиления. Также есть функция, позволяющая проверить, запущен ли музыкальный проигрыватель на целевом устройстве:

-- Если на этом iPhone/Android-устройстве воспроизводится звук, заглушить все
if sound.is_music_playing() then
    for i, group_hash in ipairs(sound.get_groups()) do
        sound.set_group_gain(group_hash, 0)
    end
end

Группы идентифицируются с помощью хэш-значения. Строку имени можно получить с помощью sound.get_group_name(), которую можно использовать для отображения имен групп в инструментах разработки, например, в микшере для тестирования уровней групп.

Sound group mixer

::: important Вы не должны писать код, который полагается на строковое значение звуковой группы, поскольку они недоступны в релизных сборках. :::

Все значения линейны в диапазоне от 0 до 1.0 (0 dB). Для преобразования в децибелы просто используйте стандартную формул:

db = 20 \times \log \left( gain \right)
for i, group_hash in ipairs(sound.get_groups()) do
    -- Строка имени доступна только в отладке. В релизе возвращается "unknown_*".
    local name = sound.get_group_name(group_hash)
    local gain = sound.get_group_gain(group_hash)

    -- Преобразовать в децибелы.
    local db = 20 * math.log10(gain)

    -- Получите RMS (среднеквадратичное значение коэффициента усиления). Левый и правый канал отдельно.
    local left_rms, right_rms = sound.get_rms(group_hash, 2048 / 65536.0)
    left_rmsdb = 20 * math.log10(left_rms)
    right_rmsdb = 20 * math.log10(right_rms)

    -- Получить пик усиления. Левый и правый отдельно.
    left_peak, right_peak = sound.get_peak(group_hash, 2048 * 10 / 65536.0)
    left_peakdb = 20 * math.log10(left_peak)
    right_peakdb = 20 * math.log10(right_peak)
end

-- Группе "master" задать усиление +6 dB (math.pow(10, 6/20)).
sound.set_group_gain("master", 1.995)

Фильтрация звуков

Если игра воспроизводит один и тот же звук по событию, и это событие срабатывает часто, существует риск воспроизведения одного и того же звука два раза или более одновременно. Если это произойдет, звуки будут сдвинуты по фазе, что может привести к появлению очень заметных артефактов.

Phase shift

Самый простой способ решить эту проблему --- построить шлюз, который будет фильтровать звуковые сообщения и не позволит воспроизводить один и тот же звук более одного раза в течение заданного интервала времени:

-- Не допустить воспроизведение одного и того же звука в течение интервала "gate_time".
local gate_time = 0.3

function init(self)
    -- Store played sound timers in a table and count down each frame until they have been
    -- in the table for "gate_time" seconds. Then remove them.
    self.sounds = {}
end

function update(self, dt)
    -- Count down the stored timers
    for k,_ in pairs(self.sounds) do
        self.sounds[k] = self.sounds[k] - dt
        if self.sounds[k] < 0 then
            self.sounds[k] = nil
        end
    end
end

function on_message(self, message_id, message, sender)
    if message_id == hash("play_gated_sound") then
        -- Only play sounds that are not currently in the gating table.
        if self.sounds[message.soundcomponent] == nil then
            -- Store sound timer in table
            self.sounds[message.soundcomponent] = gate_time
            -- Play the sound
            sound.play(message.soundcomponent, { gain = message.gain })
        else
            -- An attempt to play a sound was gated
            print("gated " .. message.soundcomponent)
        end
    end
end

Чтобы использовать шлюз, достаточно отправить ему сообщение play_gated_sound и указать целевой звуковой компонент и усиление звука. Шлюз вызовет sound.play() с целевым звуковым компонентом, если шлюз открыт:

msg.post("/sound_gate#script", "play_gated_sound", { soundcomponent = "/sounds#explosion1", gain = 1.0 })

::: important Не получится заставить шлюз слушать сообщения play_sound, поскольку это имя зарезервировано движком Defold. Вы получите неожиданное поведение, если будете использовать зарезервированные имена сообщений. :::

Манипулирование при выполнении

Звуками можно управлять во время выполнения с помощью ряда различных свойств (обращайтесь к документации по API). Следующими свойствами можно манипулировать с помощью go.get() и go.set():

gain : Усиление для звукового компонента (number).

pan : Панорамирование звукового компонента (number). Панорамирование должно быть значением между -1 (-45 градусов влево) и 1 (45 градусов вправо).

speed : Скорость звукового компонента (number). Значение 1.0 --- нормальная скорость, 0.5 --- половина скорости и 2.0 --- двойная скорость.

sound : Путь к звуковому ресурсу (hash). Путь к ресурсу может быть использован для изменения звука с помощью resource.set_sound(path, buffer). Пример:

local boom = sys.load_resource("/sounds/boom.wav")
local path = go.get("#sound", "sound")
resource.set_sound(path, boom)

Конфигурация проекта

В файле game.project имеются несколько настроек проекта, относящихся к звуковым компонентам.

Потоковое воспроизведение звука

Также возможно использование потокового воспроизведения звуков.