О проигрывающем устройстве aud

Список разделов Геймдев в Blender Игровой движок Blender

Описание: Все вопросы и обсуждения, касающиеся BGE
Модераторы: exooman, denis8424

Сообщение #1 Август » 13.02.2019, 14:22

Извиняюсь ребята. Повторяюсь в новой теме. В предыдущей что-то не срослось.
Но тут нарисовался ещё один нюанс. В конструкции:
Код: Выделить всё
    if sensR.positive == True:                     # если нажата клавиша Стрелка вниз, то
        sound = aud.Factory.file(bge.logic.expandPath('//Звук2.mp3'))    # получить файл звука2
        sound_device = aud.device()                 # получить устройство звука
        sound_handle = sound_device.play(sound)     # включить проигрывание устройства звука                 
       ................................
... если за включением проигрывающего устройства Звука2, включить включение Звука3 через такую же конструкцию, то проигрыш Звука2 не осуществляется, а сразу идёт проигрыш Звука3.
Вопрос в следующем, можно ли создать условие перехода к Звуку3 только в случае окончания проигрыша Звука2, т.е. каким-то образом отметить (обнаружить) окончание проигрыша Звука2?
Август M
Сообщения: 163

Сообщение #2 Bibo » 13.02.2019, 17:51

В условии сделать
Код: Выделить всё
if sensR.positive and sound_handle.status:
Bibo
Аватара
Сообщения: 540

Сообщение #3 Август » 13.02.2019, 18:34

Bibo писал(а):
Bibo » 31 минуту назад
В условии сделать
if sensR.positive and sound_handle.status:
Bibo, как я понимаю здесь status состояние файла проигрывания звукового файла?
В описании нашёл:
status - Воспроизводится ли звук, приостановлен или остановлен (=неверно).
Значит интересующий статус как-то надо определить. А вот как определить именно конец? Куда-то надо end прилепить, или я не так понимаю?
Август M
Сообщения: 163

Сообщение #4 Bibo » 13.02.2019, 19:39

Август писал(а):Bibo, как я понимаю здесь status состояние файла проигрывания звукового файла?
status принимает значение False если проигрывание было остановлено или если проигрывание подошло к концу. Принимает True если проигрывание идет или поставлено на паузу. То есть достаточно проверить, является ли status проверяемого звука False.
Bibo
Аватара
Сообщения: 540

Сообщение #5 Август » 13.02.2019, 21:08

Bibo писал(а):status принимает значение False если проигрывание было остановлено или если проигрывание подошло к концу. Принимает True если проигрывание идет или поставлено на паузу. То есть достаточно проверить, является ли status проверяемого звука False
Что-то типа:
if sound_device.status == False:
Я правильно понял? Грамматика присоединения status через точку?
Август M
Сообщения: 163

Сообщение #6 Bibo » 13.02.2019, 21:38

Август писал(а):if sound_device.status == False:
Я правильно понял? Грамматика присоединения status через точку?
Ага.
Bibo
Аватара
Сообщения: 540

Сообщение #7 Август » 13.02.2019, 22:15

Bibo писал(а):Ага.
Спасибо Bibo за помощь. Вроде заработало. Завтра в код вставлю, посмотрю, а то я тут уже циклы задержки стал мастерить-подбирать. Удачи.

Добавлено спустя 13 часов 47 минут:
Август писал(а):Спасибо Bibo за помощь. Вроде заработало. Завтра в код вставлю, посмотрю, а то я тут уже циклы задержки стал мастерить-подбирать. Удачи.
Нет Bibo, не заработало.
Опробовал строку:
if sound_device.status == False:
Получил ошибку:
AttributeError: 'aud.Device' object has no attribute 'status'
Опробовал строку:
if sound_status == False:
Получил ошибку: NameError: name 'sound_status' is not defined
Опробовал строку:
Handle = aud.Handle
..........................
if Handle.status == False:
Проскочил мимо. Опробовал строку:
hand = Handle.status
print("======Handle.status == ", hand)
Получил ответ: <attribute 'status' of 'aud.Handle' objects>
Атрибут status вроде бы получил, а распознать его не получается. Всё. Упёрся в стену.
Если очень докучаю, может ссылку на вразумительное пояснение отыщите, а если найдёте возможность просто подсказать, то буду очень признателен.
Август M
Сообщения: 163

Сообщение #8 Bibo » 14.02.2019, 18:59

Обрати внимание что в моем сообщении шла речь о переменной sound_handle, а не о sound_device
Август писал(а):sound_handle = sound_device.play(sound)
sound_device.play(sound) запускает воспроизведение звука. Оператором = ты сохраняешь специальный объект, посредством которого можно контролировать процесс воспроизведения, в переменную sound_handle. Именно этот объект содержит атрибут status через точку.
Bibo
Аватара
Сообщения: 540

Сообщение #9 denis8424 » 14.02.2019, 19:09

Август, у меня почему-то возникло ощущение что ты каждый раз при запуске скрипта создаешь новую переменную handle. Я попробовал сохранять её как проперти обьекта и УМВР. Сделал на коленке маленький пример, но я эту библиотеку никогда раньше не использовал так что без комментариев
https://drive.google.com/file/d/1xTOErWdYVVn2yVbk6PhSTySmtJULowNA/view?usp=drivesdk
denis8424
Аватара
Сообщения: 724

Сообщение #10 Август » 14.02.2019, 20:50

denis8424 писал(а):Август, у меня почему-то возникло ощущение что ты каждый раз при запуске скрипта создаешь новую переменную handle. Я попробовал сохранять её как проперти обьекта и УМВР. Сделал на коленке маленький пример, но я эту библиотеку никогда раньше не использовал так что без комментариев
Денис, если честно я и сам толком никак не пойму что я делаю. Вот и пытаюсь разобраться. Твой пример это то, что мне в общем-то и нужно.
Код: Выделить всё
if sensR.positive == True:                     # если нажата клавиша Стрелка вниз, то
        sound = aud.Factory.file(bge.logic.expandPath('//Звук2.mp3'))    # получить файл звука2
        sound_device = aud.device()                 # получить устройство звука
        sound_handle = sound_device.play(sound)     # включить проигрывание устройства звука   
        if sens.positive and 'handle' in own and own['handle'].status == False:
                  sound = aud.Factory.file(bge.logic.expandPath('//Звук3.mp3'))    # получить файл звука3
Денис, мой плагиат верен? Проверить не могу у меня очень шумно - сосед стены штробит (два часа пыток шумом вторую неделю по вечерам).
И, ещё, 'handle' in own, это как понять, что такое 'handle'? Меня интересует не перевод английского слова.
Август M
Сообщения: 163

  • 1

Сообщение #11 denis8424 » 15.02.2019, 13:06

Август писал(а):Денис, если честно я и сам толком никак не пойму что я делаю.
Многабукв
Давай попробуем разобраться, глядишь кто подскажет, если заметят неточность или ошибку. Код я писал из головы, могут быть ошибки!
Итак, как написано в документации, класс aud.Device предоставляет возможность взаимодействия с аппаратной частью, сиречь со звуковой картой, через соответствующие библиотеки, в общем, это устройство вывода звука. Есть нюансы, но для простоты будем считать так. В это устройство мы отправляем объект свежесозданный aud.Factory. Название прямо намекает, что на этом заводе - фабрике производится звук из файла, то есть осуществляется загрузка/подгрузка с диска в память(музыка ведь и большого размера может быть), разжатие звука из какого- нибудь .ogg или .mp3 итак далее. Кстати, обращаю внимание, что в моём примере я задавал Factory без использования функции aud.Factory.file(filename) . Понятия не имею, почему это работает, у тебя сделано правильно, так и делай. Созданный Factory отправляется в устройство вывода звука делать там свои черные дела, а нам оставляет объект aud.Handle, ручки, то бишь рукоятки управления. Лично мне проще думать о нем как о приборной панели, кнопочки там, индикаторы разные.
Что это и с чем едят, вроде понятно, теперь пройдемся по логике. Начнем с того, что мы нажали на клавишу и контроллер начал исполнение скрипта. Как обычно, подгружаются библиотеки и прочее, вот мы доходим до
Код: Выделить всё
if sensR.positive == True: # Правда зачем надо "==True" ?
В этот момент у тебя создается устройство, фабрика и ручки. Как бы все замечательно, звук отправляется на фабрику, фабрика на устройство, все играет, но если уже на следующем тике клавиша снова окажется нажатой, то будет создан новый комплект ручки-фабрики, а со старым уже работать будет невозможно, он доиграет до конца и с чувством выполненного долга удалится из памяти. Поэтому нам надо сохранить доступ к ручкам между запусками скрипта. В принципе логично сделать это в виде проперти объекта, на котором висит скрипт, хотя можно и в bge.globalDict засунуть или еще куда, так что так что при первом запуске пишем ручки в проперти, то самое 'handle' , которые тебя так интересовало:
Код: Выделить всё
own['sound_handle'] = sound_device.play(sound)
Однако теперь при каждом запуске скрипта опять будет происходить создание нового набора, но только обьект ручек будет постоянно перезаписываться в свойство объекта, а старое оттуда удаляться. То есть нужно организовать проверку наличия проперти у обьекта. Правильно получить список имен проперти объекта с помощью функции bge.types.KX_GameObject.getPropertyNames и проверить входит ли в него интересующее нас имя с помощью оператора in.
Код: Выделить всё
if sensorR.positive:
    # если проперти с таким именем у объекта нет, то создаем проперти и наш набор звук, фабрика, устройство
    if 'sound_handle' not in own.getPropertyNames():
        sound = aud.Factory.file(bge.logic.expandPath('//Звук2.mp3'))    # получить файл звука2
        sound_device = aud.device()                # получить устройство звука
        own['sound_handle'] = sound_device.play(sound)     # включить проигрывание устройства звука
    # если есть, то проверяем, каков статус того звука, ручки от которого в проперти сохранены
    elif own['sound_handle'].status == False:  # если звук уже не играет, то грузим новый набор
        sound = aud.Factory.file(bge.logic.expandPath('//Звук3.mp3'))    # получить файл звука3
        sound_device = aud.device()                # получить устройство звука
        own['sound_handle'] = sound_device.play(sound)     # включить проигрывание устройства звука
    elif own['sound_handle'].status == True:    # если звук еще играет, то ничего не делаем, эта ветка не нужна
        pass                                                   # я её добавил для наглядности     

Есть еще один нюанс, дело в том, что ссылка на ручки сохраняется в свойстве объекта, поэтому даже уже отработавшая фабрика скорее всего остается висеть в памяти, порождая утечку памяти, поэтому после использования звука нужно освобождать его ручки из проперти объекта. Самый простой способ - просто присвоить свойству значение None:
Код: Выделить всё
if always.positive and 'sound_handle' in own.getPropertyNames():
    own['sound_handle'] = None
Пусть будет дополнительный сенсор, а то и целый скрипт, который будет раз в секунду-пять проверять наличие и статус проперти. Теоретически, можно удалять само проперти из объекта, но пожалуй, лучше этого не делать, как бы BGE не упал.
Но! Теперь в нашем проперти с ручками может оказаться и не ручки вовсе, а пустой объект, обращение к статусу которого породит ошибку, поэтому надо добавить к проверке статуса еще и проверку, не пустышка ли у наc, примерно так:
Код: Выделить всё
elif own['sound_handle'] != None and own['sound_handle'].status == False:
denis8424
Аватара
Сообщения: 724

Сообщение #12 Август » 15.02.2019, 15:40

denis8424 писал(а):Многабукв
denis8424, очень, очень, очень благодарен за столь полный ответ. Скажу честно, "шандарахнул" по мозгам весьма прилично. Буду осваивать полученный урок. Боюсь что это может занять много времени, но может и вскоре потребоваться какое-либо уточнение.
Прошу, наведывайся в тему при наличии свободного времени, ну и желании помочь разобраться. Очень доволен разъяснением. Удачи во всём.
Август M
Сообщения: 163

Сообщение #13 Август » 16.02.2019, 11:16

denis8424 писал(а):Однако теперь при каждом запуске скрипта опять будет происходить создание нового набора, но только обьект ручек будет постоянно перезаписываться в свойство объекта, а старое оттуда удаляться. То есть нужно организовать проверку наличия проперти у обьекта. Правильно получить список имен проперти объекта с помощью функции bge.types.KX_GameObject.getPropertyNames и проверить входит ли в него интересующее нас имя с помощью оператора in.
КОД: ВЫДЕЛИТЬ ВСЁ
if sensorR.positive:
    # если проперти с таким именем у объекта нет, то создаем проперти и наш набор звук, фабрика, устройство
    if 'sound_handle' not in own.getPropertyNames():
        sound = aud.Factory.file(bge.logic.expandPath('//Звук2.mp3'))    # получить файл звука2
        sound_device = aud.device()                # получить устройство звука
Добрый день Денис. При запуске кода получил:
Код: Выделить всё
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Svuk
14=====sensG.positive ==  False sensR.positive ==   False car[GasRev] ==  0
Python script error - object 'Car', controller 'Python.006':
Traceback (most recent call last):
  File "Svuk", line 22, in <module>
KeyError: 'value = gameOb[key]: KX_GameObject, key "sound_handle" does not exist
Решил в стартовом скрипте получить первый набор звука, чтобы уйти от ошибки таким кодом:
Код: Выделить всё
if 'sound_handle' not in own.getPropertyNames(): # если свойства с таким именем у объекта нет, то ...
        sound = aud.Factory.file(bge.logic.expandPath('//Звук2.mp3')) # ... создаем свойство и наш файл звука запуска двигателя
        sound_device = aud.device()                 # получить устройство звука
        print("64======Start == sound", sound)
однако запускать звук не стал. Посчитал что возможно запустить в звуковом скрипте.
Нарисовалась такая картинка:
Blender Game Engine Started
Код: Выделить всё
7!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Start
62======Start == sound_handle not in own.getPropertyNames() True
64======Start == sound <aud.Factory object at 0x000000000CA09B10>

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Svuk
14=====sensG.positive ==  False sensR.positive ==   False car[GasRev] ==  0
Python script error - object 'Car', controller 'Python.006':
Traceback (most recent call last):
  File "Svuk", line 22, in <module>
KeyError: 'value = gameOb[key]: KX_GameObject, key "sound_handle" does not exist
Консоль утверждает что при старте звуковой файл получен, но в скрипте Svuk отсутствует и с упорством маньяка твердит об этом при каждом обращении к скрипту Svuk.
Однако после нажатия на клавишу ошибка пропадает. Конечно можно сделать при первом обращении к скрипту Svuk, при отсутствии нажатия на клавиши объявление первого набора звука, но мой вопрос о другом. И в документации, и ты утверждаешь что "отработавшая фабрика скорее всего остается висеть в памяти, порождая утечку памяти", которую я не вижу, ведь ошибка говорит об отсутствии "sound_handle".
Я что-то недопонимаю?
Да, ещё, в коде own, это own = cont.owner?
Жду ответа, как соловей лета.
Август M
Сообщения: 163

Сообщение #14 denis8424 » 16.02.2019, 22:44

Ты бы полный текст скрипта выложил на почитать.
Да, own это cont.owner

Тебе бы про жизненный цикл обьекта почитать, но если вкратце - если нет ни одной действующей ссылки(переменной) на обьект, то сборщик мусора удаляет этот обьект. Но если у нас где-то в проперти игрового обьекта лежит ссылка на обьект ручек, то логично предположить, что и обьект фабрики будет существовать, пока игровой обьект не будет удален.
denis8424
Аватара
Сообщения: 724

Сообщение #15 Август » 17.02.2019, 15:37

denis8424 писал(а):Ты бы полный текст скрипта выложил на почитать.
Да, own это cont.owner
Без проблем, только я его курочу постоянно и вполне возможно что что-то от предыдущих попыток осталось в нём.
Вот то, что на данный момент есть:
https://my-files.ru/4f3g4d
Звуки, правда не обработанные, просто взял несколько фрагментов:
https://my-files.ru/wzsc5o
https://my-files.ru/xe8tqw
https://my-files.ru/gcoxxa
https://my-files.ru/08jijn
На цифровой клавиатуре стрелки. 8 - включение двигателя и увеличение скорости вперёд. Задняя должна быть на 2, но пока не пытался - с движением вперёд надо разобраться для начала.
Про жизненный цикл объекта не прочь был бы почитать.
Август M
Сообщения: 163

Сообщение #16 Август » 19.02.2019, 12:47

denis8424 писал(а):Сделал на коленке маленький пример, но я эту библиотеку никогда раньше не использовал так что без комментариев
https://my-files.ru/zjf7un
denis8424, я немного изменил код, коль есть время и желание взгляни. Вопрос в том, что есть прерывистость звукового файла. Есть возможность избавиться от этой прерывистости?
Август M
Сообщения: 163

Сообщение #17 Wegemu » 19.02.2019, 16:24

denis8424, я немного изменил код, коль есть время и желание взгляни. Вопрос в том, что есть прерывистость звукового файла. Есть возможность избавиться от этой прерывистости?
Не надо каждый тик загружать аудиофайл заново с харда и воспроизводить его. Вы хоть вообще понимаете что делаете то? Или методом тыка? :) Прерывистость из-за over 99999 одновременной загрузки и воспроизведения файла. Зачем? Поправил. Да, и хендл аудио можно зациклить (loop_count). Все для этого есть, только спеку читать надо. ;)

aud.blend.zip

P.S. + в mp3-файле в начале и в конце надо подрезать для пущего эффекта.
When debugging, novices insert corrective code; experts remove defective code.
VEゲーム

Ушел в поисках приключений в страну GLSL.
Wegemu M
Аватара
Сообщения: 61

Сообщение #18 Август » 19.02.2019, 17:16

Wegemu писал(а):Не надо каждый тик загружать аудиофайл заново с харда и воспроизводить его. Вы хоть вообще понимаете что делаете то? Или методом тыка?
Точнее будет сказать методом плагиата. Вот потому что я не очень понимаю, но пытаюсь понять я здесь. Какими строками я "загружаю аудиофайл заново с харда и воспроизвожу его" - own['handle'] = device.play(factory)?
Прерывистость из-за over 99999 одновременной загрузки и воспроизведения файла. Зачем? Поправил. Да, и хендл аудио можно зациклить (loop_count). Все для этого есть, только спеку читать надо.
aud.blend.zip
Wegemu, похоже что архив запорчен, звукового файла нет. Ведь "sound_engine_0 = '/home/kurai/Загрузки/engine_0.mp3'" это загрузка файла или я ошибаюсь? В общем у меня ничего не происходит после нажатия на пробел
P.S. + в mp3-файле в начале и в конце надо подрезать для пущего эффекта.
Пытался подрезать. Я видел в начале и конце файла захват пустоты. Однако Sound Forge Pro 10.0, на котором я пытался подрезку произвести упорно эту пустоту образует.

P.S.
Вообще чертовщина какая-то, принтов наставил чуть не к каждой строке, а выдаёт:
Blender Game Engine Started
Blender Game Engine Finished
Видно не мой день сегодня, отложу до завтра.
Август M
Сообщения: 163

Сообщение #19 Wegemu » 20.02.2019, 16:46

Wegemu, похоже что архив запорчен, звукового файла нет. Ведь "sound_engine_0 = '/home/kurai/Загрузки/engine_0.mp3'" это загрузка файла или я ошибаюсь? В общем у меня ничего не происходит после нажатия на пробел

Я забыл упаковать звук. Да, в строке 14 поменять надо на свое:
Код: Выделить всё
sound_engine_0 = '/home/kurai/Загрузки/engine_0.mp3'

Загрузку звуков (factory) нужно делать один раз при запуске, те что будут использоваться часто можно буфферизировать (буфер в ОЗУ). Какой смысл каждый тик считывать файл с харда? Верно, никакого.

Изображение
When debugging, novices insert corrective code; experts remove defective code.
VEゲーム

Ушел в поисках приключений в страну GLSL.
Wegemu M
Аватара
Сообщения: 61

Сообщение #20 Август » 21.02.2019, 08:43

Wegemu писал(а):Загрузку звуков (factory) нужно делать один раз при запуске, те что будут использоваться часто можно буфферизировать (буфер в ОЗУ). Какой смысл каждый тик считывать файл с харда? Верно, никакого.
Об этом я хотел спросить следующим вопросом, что такое этот буфер, как его организовать в коде если звуков несколько?
Август M
Сообщения: 163

След.

Вернуться в Игровой движок Blender