Звук в Java

    Часто в приложениях желательно использовать какие-то вспомогательные звуковые эффекты, например пикнуть динамиком при ошибке или проиграть мелодию на новое письмо.
    Не все знают что в любом компьютере имеющем звуковую карту встроена большая библиотека звуков. Все звуковые платы поддерживают воспроизведение звука по стандарту MIDI (см. ru.wikipedia.org/wiki/MIDI) а это 128 обычных и 40 ударных инструментов.

    Что такое MIDI — это стандарт на команды управления синтезатором или другими устройствами воспроизведения звука. Т.е. в .mp3, например, хранится оцифрованный звук а в файлах .mid только ноты которые воспроизводит звуковая карта.

    Я опубликовал библиотеку для простого доступа к воспроизведению MIDI-звука:

    image


    Исходный код с примером использования а так же скомпилированную библиотеку можно скачать на странице http://code.google.com/p/easy-midi/

    Преимущества MIDI: есть в любом компе, содержит 128 обычных и 40 ударных инструментов воспроизводится муз.сопроцессором и не влияет на производительность воспроизводимую музыку можно интерактивно менять (если понимать чем диез от бемоля отличается).
    Недостатки: звучание полностью зависит от звуковой карты и на разных компах может отличаться.

    Пример простого вызова (играет в отдельном потоке):

    Tools.playNote(Note.p93_7_La, Note.i127_Gunshot,127, 2000);
    Tools.playDrum(Drum.d39_Hand_Clap, 127, 2000);
    

    Названия нот и обычных инструментов для удобства заданы константами в файле Note.java, названия ударных инструментов в файле Drum.java.

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

    int bassVoice=Note.i33_Electric_Bass_finger;
    Drum hat=new Drum(4, Drum.d42_Closed_Hi_Hat,64);
    Drum snare=new Drum(4, Drum.d38_Acoustic_Snare);
    Drum bass=new Drum(4, Drum.d35_Acoustic_Bass_Drum);
    Phrase p1=new Phrase()
            .chord(new Chord(8).drum(hat).drum(bass)        .note(8, Note.p28_2_Mi, bassVoice))
            .chord(new Chord(8).drum(hat)                   .note(8, Note.p28_2_Mi, bassVoice))
            .chord(new Chord(8).drum(hat).drum(snare)       .note(8, Note.p28_2_Mi, bassVoice))
            .chord(new Chord(8).drum(hat)                   .note(8, Note.p28_2_Mi, bassVoice))
            .chord(new Chord(8).drum(hat).drum(bass)        .note(8, Note.p28_2_Mi, bassVoice))
            .chord(new Chord(8).drum(hat).drum(bass)        .note(8, Note.p28_2_Mi, bassVoice))
            .chord(new Chord(8).drum(hat).drum(snare)       .note(8, Note.p34_2_La_Diese, bassVoice))
            .chord(new Chord(8).drum(hat)                   .note(8, Note.p35_2_Si, bassVoice))
    ;
    Ticker ti = new Ticker(120, p1);
    ti.restart();
    

    Описание классов


    Tools — содержит методы playNote и playDrum для воспроизведения единичных звуков
    Ticker — проигрыватель фраз
    Phrase — музыкальная фраза, содержит набор аккордов
    Chord — аккорд, содержит высоту и длительность нот обычных и ударных инструментов аккорда
    Drum — описание ударного инструмента в аккорде
    Note — описание обычного инструмента в аккорде
    Метки:
    Поделиться публикацией
    Похожие публикации
    Комментарии 49
    • +5
      Теперь собрать воедино MIDI звук и Java 2D графику и снова написать pacman.
    • –5
      Извините, но прошлый век.
      У меня где-то лежит самописная библиотека на JNI позволяющая выводить видео и звук на Java, сделанная на DirectShow… могу если интересно написать статью, если когда-нибудь карма вырастет.
      • 0
        Зачем выводить MIDI-звук через DirectShow который подключен через JNI если можно это сделать напрямую.
        • –6
          Речь о выводе любого звука или видео, кодек которого представлен в системе и известен DirectShow-у
          • 0
            процитирую

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

            Если стоит задача проиграть, скажем, аплодисменты по окончанию загрузки в базу или ещё что то можно использовать

            Tools.playNote(…

            а можно подключить DirectShow, JNI, заказать у проф.музыканта семпл и встроить его в приложение.

            Результат будет одинаковый с точки зрения пользователя но первый способ, стесняюсь говорить об очевидном, как-то проще, быстрее и дешевле.
        • +3
          в чём смысл использования доступного только в Windows DirectShow на кроссплатформенном Java?
        • +3
          Java активизировалась на главной, приятно.
          Но неужели все настолько примитивно и плачевно?

          Монстр, который запускается с минимальными изменениями на огромном количестве операционных систем (без шуток про универсальность и анальный секс), гибко масштабируется, позволяет написать полноценное приложение с мозгом на сервере, управлением на рабочих станциях и клиентами для мобильных устройств…
          … а в постах примитивная графика, эпохи 90-х, и проигрывание нот из MIDI ))
          • НЛО прилетело и опубликовало эту надпись здесь
            • 0
              я бы посоветовал выбирать выражения. Стандарт MIDI, в той части которая касается этой библиотеки (воспроизведение звука), поддерживается практически всеми звуковыми картами. В этом можно убедиться запустив тестовое приложение.

              Что касается аппаратного MIDI то в статье оно не упоминается и библиотеки никак не касается.
              • +1
                Что касается аппаратного MIDI то в статье оно не упоминается и библиотеки никак не касается.
                Зато в статье упоминается вот это:
                в любом компьютере имеющем звуковую карту встроена большая библиотека звуков. Все звуковые платы поддерживают стандарт MIDI
                Думаю, про это и имелось ввиду всеми кто написал про «поддержку MIDI». И всё верно говорят, потому как эта ваша фраза в корне неверна и некорректна. А вы грубите зачем-то. Ничего давно не встроено, никто давно не поддерживает.
                • 0
                  ок, добавил в текст «воспроизведение звука».

                  — Ничего давно не встроено, никто давно не поддерживает.
                  — это можно легко проверить запустив тестовую программу.
                  • 0
                    попортился текст ответа, читать так

                    Ничего давно не встроено, никто давно не поддерживает.

                    — это можно легко проверить запустив тестовую программу.
                    • +1
                      Я всё понял! И все поняли, что у вас либа работает и музыка играет! Докопались исключительно до слов тут все. Ибо нету никакой «встроенной большой библиотеки звуков». Ибо тем более вкупе с «поддерживают стандарт MIDI» явно кажется, что Вы имели ввиду, что вся эта «библиотека» зашита в карту, либо же картой синтезируется. Но это не так.
                      • НЛО прилетело и опубликовало эту надпись здесь
                        • –1
                          ок, будем по буквам.

                          Что значит «ни одна современная карточка не умеет сама воспроизводить MIDI»?
                          На любую карточку через классы из javax.sound.midi можно подать MIDI-команду и команда будет выполнена. Например «играть инструмент 5 нотой 33 и длительностью 1 секунда». Всё будет играть и на дорогих и на дешёвых картах.

                          Далее «То что вы слышите — результат работы софтверного синтезатора» — да, Windows 7, скажем, пытается отключить хардварный синтез и использовать свой. Т.е. где-то есть хардварный, где-то софтварный. Что это значит для библиотеки EasyMIDI? Да ничего это не значит. Звук будет играть везде.

                          К чему это обсуждение? Это полный оффтоп.
                          • НЛО прилетело и опубликовало эту надпись здесь
                            • –1
                              Что это значит для библиотеки EasyMIDI? Да ничего это не значит. Звук будет играть везде.

                              К чему это обсуждение? Это полный оффтоп.
                              • НЛО прилетело и опубликовало эту надпись здесь
                                • 0
                                  есть прекрасное решение: сделать либу дающую такой же простой доступ к воспроизведению MIDI-инструментов но использующую не системный а собственный качественный синтезатор. И опубликовать статью на Хабре.

                                  Для тех кому это не нужно а достаточно воспроизведения небольших музыкальных фрагментов, EasyMIDI вполне подойдёт.
              • +3
                Эм, пардон. Ну, допустим, я даже пропущу мимо ушей гениальные фразы про «Все звуковые платы поддерживают стандарт MIDI» (разумеется, далеко не все; если уж говорить о поддержке _звуковыми_картами_ — то, если я правильно понимаю, чуть ли не последний бастион аппаратного любительского MIDI держится на ровной одной линейке звуковых карт от Creative) и «звучание полностью зависит от звуковой карты» (потому что если на звуковой карте синтезатора нет, он целиком весь софтверный, но разница будет только в используемых банках инструментов).

                Но все-таки, что вы сделали-то? Вы сделали обертку над и так существующим в Java javax.sound.midi — и всё? (который, кстати, сам по себе забавный и в Sun-овской версии таскает с собой еще свой собственный синтезатор и лицензированный набор патчей и, кстати, является одним из тех самых камней преткновения, почему Sun не может просто так отдавать всю Java как redistributable)

                Вы понимаете, что вот этим вот вы банально перечеркнули все многолетние старания апологетов стандарта MIDI про синхронизацию, про clock, про состояния sequencer'а и т.д.? Зачем все это?..
                • –4
                  процитирую

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

                  Это часто встречаемая, вполне типовая задача.
                  • +1
                    В *приложениях* надо решать задачи, ставящиеся перед приложениями, а не «использовать вспомогательные звуковые эффекты». Если приложению нужно сигнализировать об ошибке — то для этого в каждой современной операционной среде есть штатные механизмы алертов — в том числе среда там и звук сделает, какой пользователю хочется, и лампочками мигнет, и эффектик какой-нибудь покажет, и смску на телефон отправит при желании. Не стоит делать приложения, которые самодеятельно вдруг решают, что пользователю будет внезапно интересно послушать мелодию в качестве индикатора события.

                    Но я, в общем, даже не об этом. Чем вас API javax.sound.midi-то не устроил? Я пока только одно отличие вижу — тем, что там нет констант?..
                    • +1
                      В приложении надо решать задачи. Если задачей является «использовать вспомогательные звуковые эффекты» то надо решать именно эту задачу а не какие-то другие.

                      API javax.sound.midi не позволяет по-простому проиграть музыкальный фрагмент или отдельный звук. Данная библиотека предоставляет такую возможность (см. пример в каментах выше) одной строкой

                      Tools.playNote(…

                      Кроме того, во многих приложениях (казуальные игры) желательно менять воспроизводимую композицию для отражения того что происходит на экране. Если сравнить с API Android то там для этих целей используется http://developer.android.com/reference/android/media/JetPlayer.html — в файле заранее готовятся куски MIDI-фрагментов и их можно воспроизводить меняя последовательность на ходу.

                      API javax.sound.midi простого пути для подобного не предоставляет. В EasyMIDI это достаточно легко делается.

                      Не очень понятно почему вообще идёт речь о синхронизации и соответствии требованиям стандарта MIDI. У библиотеки чётко очерчена область применения в начале статьи. И эта область гораздо обширней (по количеству приложений) задач написания муз.произведений.
                • +5
                  Круто, музыка на ООП. new Mozart().getSymphony(40).play().
                  • –1
                    Ни кто не мешает вам реализовать данное действие) Сокрыв под getSymphony обращение к серверу для получения ссылки на поток или скачивания его на компьютер и последующего воспроизведения :-)
                    • 0
                      • 0
                        всё, я нашел свое призвание
                    • 0
                      Пакеты MIDI в Java не будут работать в Linux, так как машина не знакома с Jack и ALSA.

                      Для тех, кто ищет тру кроссплатформенную библиотеку для работы с MIDI, рекомендую библиотеку rtMIDI для C++. Вместе с интерфейсом на Qt можно кое-что сделать.
                      • 0
                        это блог по Java а не по C++ или QT
                        • +1
                          Да нормально всё, в общем, работает. Jack там не при чем, Jack-синтезаторы, если уж на то пошло, прекрасно через ALSA sequencer API умеют общаться.

                          А rtMIDI как раз странная, на самом деле — в первую очередь непонятно, как предполагается решать в ней типовую задачу «поставили играть MIDI, хотим отрисовывать progress bar / курсор на текущей ноте». User callback там только на входящие потоки предусмотрены. Мне больше нравится TSE3 — он хотя бы логически более стройный, правда, не обновляется уже давно…
                          • 0
                            У меня на линуксе пример не заработал. Я уже и тимидити к нему поставил, всё-равно не работает. Jack'а правда нету, но вряд ли в нём дело.
                            javax.sound.midi.MidiUnavailableException
                            at javax.sound.midi.MidiSystem.getDefaultDeviceWrapper(MidiSystem.java:1078)

                            Caused by: java.lang.IllegalArgumentException: Requested device not installed
                            • 0
                              Это при выполнении какой операции?
                              • 0
                                Это при запуске демо. (
                                • –1
                                  ну, у линукса есть некоторые проблемы с MIDI из Java (у меня OpenSUSE). Руки не дошли пока всё отладить, я не Oracle чтоб за них всё проверить под разными ОС. Сделаю workaround со временем.

                                  Тут выше советуют выбросить Java и перейти на C++. Можно у них спросить.
                                  • 0
                                    Вам выше сказали уже почему так. А под виндой будет такая «midi» (та, что генерится синтезатором своим JRE-шным), что лучше бы его не было)
                                    • –1
                                      я и написал что сделаю workaround для пользователей как руки дойдут.

                                      По поводу «что лучше бы его не было» — никто не неволит. Можно использовать то что советовали выше, можно без MIDI и можно вообще без Java.
                                  • 0
                                    Ех… Stack trace целиком покажите — на каком именно вызове API это падает?
                                    И еще — JRE какая — Sun'овская, OpenJDK, Harmony и т.д.?
                                    • 0
                                      Sun'овская JRE, полный стектрейс только вечером будет.
                                      • 0
                                        init EasyMIDI
                                        javax.sound.midi.MidiUnavailableException
                                        at javax.sound.midi.MidiSystem.getDefaultDeviceWrapper(MidiSystem.java:1078)
                                        at javax.sound.midi.MidiSystem.getSynthesizer(MidiSystem.java:307)
                                        at midi.Tools.initSynthesizer(Tools.java:17)
                                        at midi.Demo.(Demo.java:49)
                                        at midi.Demo.main(Demo.java:94)
                                        Caused by: java.lang.IllegalArgumentException: Requested device not installed
                                        at javax.sound.midi.MidiSystem.getDefaultDevice(MidiSystem.java:1130)
                                        at javax.sound.midi.MidiSystem.getDefaultDeviceWrapper(MidiSystem.java:1076)
                                        ... 4 more
                                        Exception in thread "main" java.lang.NullPointerException
                                        at midi.Tools.initSynthesizer(Tools.java:27)
                                        at midi.Demo.(Demo.java:49)
                                        at midi.Demo.main(Demo.java:94)
                                        • 0
                                          Ну это в самом-самом начале, значит. У вас JRE без поддержки MIDI вообще — т.е. своего синтезатора с банками в ней нет, во внешние она не смотрит. Можно их скачать и установить дополнительно — с другой стороны — нафига оно вам?..
                                          • 0
                                            Странно, но soundbank.gm уже стоит. Скачал soundbank-deluxe.gm — и нифига. Хм, покопаюсь ещё) Сколько уже на Java сижу, не знал, что у него такое есть))
                                            • 0
                                              Там отдельно странно и забавно то, сколько разных конфигураций-подконфигураций есть у JRE — в частности, то, что можно скачать с их сайта и то, что качается при установке пакета в дистрибутиве, могут очень радикально различаться, в том числе в этих проприетарных кусках.
                                              • 0
                                                Сейчас уже одинаковые. И падает на сановской (оракеловской) яве с их сайта 1.6.0.27. Ставил и soundbank.gm делюксовый — пофиг :(.
                              • НЛО прилетело и опубликовало эту надпись здесь
                                • 0
                                  Ну, она его на самый крайний случай таскает, справедливости ради.
                                  • 0
                                    теперь уж Оракловская, а не Сановская)
                                • +1
                                  необходимости в данном сниппете не вижу вообще… глупо… писал подобное, когда мне было скучно…
                                  • –2
                                    8)

                                    ты 1994 года? 17 лет? Писал когда было скучно?

                                    Я думаю ты преувеличиваешь свои возможности.

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