четверг, 28 января 2010 г.

Делаем звуковые эффекты

В одной из прошлых статей я обещал рассказать, как делать самостоятельно звуковые эффекты. Причём поскольку работаем мы с байтами звуковых данных, то открывается неисчерпаемое поле экспериментов.

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



При остановке записи сначала записывается заголовок (WaveHeader сам его пишет в файл), а потом открывается этот самый файл, указатель устанавливается в конец файла и пишутся звуковые данные.

Изменения звука нужно делать перед записью звуковых данных в файл. Делаются они непосредственно с байтами. Наш звук 16-разрядный, значит, одна единица звуковых данных в файле - 2 байта (16 бит). И с этой единицей можно работать.



Здесь всё сосредоточено во вложенной схеме. Сначала указатель звуковых данных в памяти устанавливается на начало. Затем размер данных делится на 2, потому что размер представлен в байтах, а извлекать надо по 2 байта, тогда цикл должен срабатывать в 2 раза меньше раз, чем размер данных.

И каждый раз цикл извлекает по 2 байта (у DataToFile Type=dtWord). Именно с этими байтами нужно что-то делать. А что - это целиком и полностью ваша фантазия. Впрочем, кое-какие примеры стоит показать. Помните только, 2 байта могут иметь 655356 вариантов, то есть число в этих пределах (0 - 65535) будет нам выдаваться.




Здесь реализуется эффект обратного воспроизведения. Точнее, плеер-то воспроизводит правильно, но в файле все байты идут задом наперёд. Посмотрите на схему. При обработке все байты записываются в массив целых чисел, а потом, когда запись закончится (т.е. выдача всех байтов закончится), начинается их обратная выдача (у ArrayEnum Type=Dec). При этом новая последовательность записывается в память, а оттуда - копируется прямиков в файл.

Что ещё можно сделать? Можно много чего сделать, однако нужно много экспериментировать или хотя бы знать, как делаются уже известные всем эффекты (типа эха, хора и т. д.). Экспериментируя со значениями байт звуковых данных, вы найдёте множество интересных и полезных конкретно для вас эффектов. А также помните, что вы всегда сможете извлечь из файла звуковые данные (их размер можно прочитать из заголовка) и вновь применять к ним эффекты.

P.S. Следите за обновлениями блога - скоро появятся новые видеоуроки ко многим предыдущим (и, возможно, текущим) статьям.






Если у вас есть свой сайт, то сервис раскрутки и продвижения сайтов в интернете вам будет обязательно нужен. От рекламы зависит посещаемость.

Сайт компании "Недвижимость и кредит" предлагает квартиры в Воронеже купить. Выгодные цены, хорошие квартиры. Рекомендую.

Перед поездкой в Тайланд, Флоренцию, Малайзию или куда угодно, узнайте отзывы туристов об отдыхе. Сходите на сайт Туристер.ру и поситайте.

4 комментария:

  1. Нет ли компонентов для других эффектов?
    А также: раньше в HiAsm был компонент для наложения эффектов на канал, где же он теперь?

    ОтветитьУдалить
  2. Старый компонент для наложеня эффектов на канал устарел безвозвратно. Он не работает с технологией менеджеров, на которую переведны все компоненты BASS. И создавать новый никто не хочет.
    Для других эффектов в HiAsm ничего нет. Да там, собственно, и не эффекты, а просто несколько модификаторов звука.
    Ну, принцип-то вам известен, суть звуковых данных ясна. Так что можете сами что-то придумать.

    ОтветитьУдалить
  3. На основании ваших проектов сделал программу-вокал ремовер (удаление вокала).

    Make(delphi)
    ver(4.04 build 184)
    Add(MainForm,2953706,21,105)
    {
    Height=100
    Caption="Удаление вокала"
    BorderStyle=3
    Position=1
    link(onCreate,15457736:doDelete,[])
    }
    Add(Label,15805043,21,252)
    {
    Left=5
    Top=10
    Width=87
    Height=17
    Caption="Исходный файл:"
    }
    Add(Edit,4113927,203,196)
    {
    Left=95
    Top=10
    Width=235
    Text=""
    link(onChange,943440:doGet,[])
    }
    Add(Button,15323027,21,196)
    {
    Left=330
    Top=10
    Caption="Обзор"
    link(onClick,3628228:doExecute,[])
    }
    Add(Button,16027011,21,308)
    {
    Left=155
    Top=40
    Width=90
    Caption="Удалить вокал"
    link(onClick,13660407:doOpen,[])
    }
    Add(ODialog,3628228,77,196)
    {
    Filter="WAV|*.wav"
    Title=""
    FileName=""
    link(onExecute,4113927:doText,[])
    }
    Add(FileStream,13660407,203,315)
    {
    link(onLoad,15538447:doEvent1,[])
    link(FileName,4113927:Text,[])
    }
    Add(Hub,15538447,259,315)
    {
    OutCount=3
    link(onEvent2,12252318:doCalc,[(291,328)(291,398)])
    link(onEvent3,16150303:doWork1,[(282,335)(282,454)])
    }
    Add(MathParse,12252318,308,392)
    {
    DataCount=1
    MathStr="%1 / 2 - 44"
    link(X1,13660407:Size,[(314,370)(216,370)])
    }
    Add(MultiElement,16150303,312,448)
    {
    link(onEvent1,463187:doEvent1,[])
    link(Data1,12252318:Result,[(318,436)(314,436)])
    link(Data2,13660407:Stream,[(325,433)(209,433)])
    }
    BEGIN_SDK
    Add(EditMulti,8730838,21,14)
    {
    EventCount=1
    WorkCount=1
    DataCount=2
    Width=874
    Height=501
    link(doWork1,13939583:doEvent1,[(73,20)(73,104)])
    }
    Add(For,16360143,210,133)
    {
    Start=1
    link(onEvent,8564489:doEvent1,[])
    link(onStop,4517232:doFor,[(254,146)(254,384)])
    link(End,312401:Var2,[])
    }
    Add(DataToFile,10041605,336,84)
    {
    Type=1
    Point(doPosition)
    link(onGet,12821300:doValue,[(373,90)(373,125)])
    link(Stream,305794:Var3,[(342,53)])
    }
    Add(Hub,13939583,126,98)
    {
    link(onEvent1,1841652:doData,[])
    link(onEvent2,16360143:doFor,[(150,111)(150,139)])
    }
    Add(DoData,1841652,231,98)
    {
    Data=Integer(44)
    link(onEventData,198992:doEvent1,[])
    }
    Add(IntegerArray,5715532,518,21)
    {
    IntArray=[]
    }
    Add(ArrayRW,13682674,518,105)
    {
    link(Array,11464727:Var2,[])
    link(Value,12821300:Value,[(538,93)(492,93)(492,163)(447,163)])
    }
    Add(Memory,12821300,441,119)
    {
    link(onData,13682674:doAdd,[])
    }
    Add(Hub,8564489,259,133)
    {
    link(onEvent1,10041605:doGet,[(297,139)(297,101)])
    link(onEvent2,11569084:doGet,[(295,146)(295,262)])
    }
    Add(DataToFile,11569084,315,245)
    {
    Type=1
    Point(doPosition)
    link(onGet,3141248:doValue,[(373,251)(373,279)])
    link(Stream,305794:Var2,[])
    }
    Add(Hub,198992,273,98)
    {
    link(onEvent1,10041605:doPosition,[])
    link(onEvent2,11569084:doPosition,[(303,111)(303,269)])
    }
    Add(IntegerArray,3932738,476,175)
    {
    IntArray=[]
    }
    Add(ArrayRW,13305406,476,259)
    {
    link(Array,13605494:Var2,[])
    link(Value,3141248:Value,[(496,247)(450,247)(450,317)(405,317)])
    }
    Add(Memory,3141248,399,273)
    {
    link(onData,13305406:doAdd,[])
    }
    Add(For,4517232,266,378)
    {
    Start=1
    link(onEvent,1765156:doOperation,[])
    link(onStop,9980276:doData,[(307,391)(307,336)(667,336)(667,258)])
    link(End,312401:Var3,[(279,124)])
    }
    Add(GetDataEx,312401,217,119)
    {
    link(Data,8730838:Data1,[(223,77)(29,77)])
    }
    Add(Hub,10556347,364,378)
    {
    link(onEvent1,1133828:doRead,[])
    link(onEvent2,3580966:doRead,[(452,391)(452,447)])
    }
    Add(Math,1765156,315,378)
    {
    OpType=1
    Op2=1
    link(onResult,10556347:doEvent1,[])
    }
    Add(ArrayRW,1133828,574,378)
    {
    link(onRead,1516077:doEvent1,[])
    link(Array,11464727:Var3,[(580,82)])
    }
    Add(GetDataEx,11464727,518,77)
    {
    link(Data,5715532:Array,[])
    }

    ОтветитьУдалить
  4. Add(MultiElementEx,732040,630,441)
    {
    @Hint=#21:Число противоположное|
    link(onInvert,1516077:doEvent2,[(670,447)(670,391)])
    link(1,3580966:Item,[(636,427)(561,427)(561,485)(531,485)])
    }
    BEGIN_SDK
    Add(EditMultiEx,12104346,21,21)
    {
    WorkCount=#88:doInvert=Выдает в поток onInvert число, противоположное числу, переданному в этом потоке|
    EventCount=#8:onInvert|
    DataCount=#1:1|
    Width=258
    Height=368
    link(doInvert,14568360:doEvent1,[(35,27)(35,34)])
    }
    Add(StrMask,14821382,84,84)
    {
    Mask="-*"
    link(onFalse,8339546:doOperation,[])
    link(onTrue,12092067:doTrim,[(135,97)(135,146)])
    }
    Add(Memory,3572919,147,28)
    {
    }
    Add(Hub,14568360,49,28)
    {
    link(onEvent1,3572919:doValue,[])
    link(onEvent2,14821382:doCompare,[(73,41)(73,90)])
    }
    Add(Math,8339546,140,84)
    {
    OpType=1
    Op1=327678
    link(onResult,10554907:doWork2,[(226,90)(226,27)])
    link(Op2,5466643:Var2,[])
    }
    Add(Trim,12092067,154,140)
    {
    Char="-"
    link(onTrim,5966681:doOperation,[])
    link(Text,5466643:Var3,[(160,68)])
    }
    Add(GetDataEx,5466643,147,63)
    {
    link(Data,3572919:Value,[])
    }
    Add(Math,5966681,210,140)
    {
    Op2=327678
    link(onResult,10554907:doWork3,[(263,146)])
    }
    Add(HubEx,10554907,259,21)
    {
    link(onEvent,12104346:onInvert,[])
    }
    END_SDK
    Add(ArrayRW,3580966,525,441)
    {
    link(onRead,15657302:doOperation,[])
    link(Array,13605494:Var3,[(531,229)])
    }
    Add(GetDataEx,13605494,476,224)
    {
    link(Data,3932738:Array,[])
    }
    Add(Math,15657302,574,441)
    {
    OpType=1
    Op2=327678
    link(onResult,732040:doInvert,[])
    }
    Add(DoData,9980276,700,252)
    {
    link(onEventData,7927977:doEvent1,[])
    link(Data,1457110:Var2,[])
    }
    Add(GetDataEx,305794,315,48)
    {
    Angle=3
    link(Data,8730838:Data2,[(36,53)])
    }
    Add(Hub,7927977,756,252)
    {
    link(onEvent1,8730838:onEvent1,[(814,258)(814,20)])
    }
    Add(Hub,1516077,679,378)
    {
    InCount=2
    OutCount=1
    link(onEvent1,13879526:doPut,[])
    }
    Add(MemoryStream,9669894,700,196)
    {
    }
    Add(DataToFile,13879526,707,378)
    {
    Type=1
    link(Stream,1457110:Var3,[(713,243)])
    }
    Add(GetDataEx,1457110,700,238)
    {
    link(Data,9669894:Stream,[])
    }
    END_SDK
    Add(WaveHeader,943440,406,189)
    {
    Point(doGet)
    Point(onGet)
    Point(varFrequency)
    Point(varChannels)
    Point(varSize)
    }
    Add(Hub,463187,364,448)
    {
    OutCount=6
    link(onEvent1,11574171:doOperation,[(385,454)(385,370)])
    link(onEvent2,11657445:doCreate,[(388,461)(388,419)])
    link(onEvent3,16512479:doData,[])
    link(onEvent4,8979798:doCopyFromStream,[(476,475)(476,440)])
    link(onEvent5,8979798:doClose,[(476,482)(476,426)])
    link(onEvent6,11388380:doExecute,[(441,489)(441,517)])
    }
    Add(WaveHeader,11657445,399,413)
    {
    FileName="temp\\tempfile.wav"
    Frequency=0
    link(onCreate,8979798:doOpen,[])
    link(Frequency,11574171:Result,[])
    link(Size,943440:varSize,[])
    }
    Add(FileStream,8979798,574,413)
    {
    FileName="temp\\tempfile.wav"
    Mode=2
    Point(doPosition)
    Point(doCopyFromStream)
    }
    Add(DoData,16512479,448,462)
    {
    link(onEventData,8979798:doPosition,[(527,468)(527,433)])
    link(Data,8979798:Size,[(454,454)(587,454)])
    }
    Add(FileTools,15457736,77,105)
    {
    DelToRecycle=1
    link(FileName,15975816:Value,[])
    }
    Add(Memory,15975816,77,56)
    {
    Default=String(temp\\tempfile.wav)
    }
    Add(Math,11574171,406,364)
    {
    OpType=2
    Op2=2
    link(Op1,943440:varFrequency,[])
    }
    Add(SDialog,11388380,511,511)
    {
    Filter="Wav|*.wav"
    Title=""
    FileName=""
    link(onExecute,1831159:doMove,[])
    }
    Add(FileTools,1831159,560,511)
    {
    link(FileName,10080160:Value,[])
    }
    Add(Memory,10080160,560,462)
    {
    Default=String(temp\\tempfile.wav)
    }

    Но есть недоделки:
    1. пробовал на частоте дискретизации 44100 гц. При использовании другой скорость была замедленной.
    2. пробовал на коротких кусках песни. при попытке удалить вокал из целой песни сказал Out of memory
    Помогите, как доделать?

    ОтветитьУдалить