На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Друзья, соблюдайте, пожалуйста, правила форума и данного раздела:
Данный раздел не предназначен для вопросов и обсуждений, он содержит FAQ-заготовки для разных языков программирования. Любой желающий может разместить здесь свою статью. Вопросы же задавайте в тематических разделах!
• Если ваша статья может быть перенесена в FAQ соответствующего раздела, при условии, что она будет оформлена в соответствии с Требованиями к оформлению статей.
• Чтобы остальным было проще понять, указывайте в описании темы (подзаголовке) название языка в [квадратных скобках]!
Модераторы: Модераторы
  
> Сохранение писка в файле , [Pascal]
    Да именно «писка», я не ошибся и опишу как сохранить в звуковом файле формата WAV (стандарт OS Windows) монотонный моно звук с прямоугольным импульсом, частотой n и длительностью звучания в микросекундах L.
    Для начала уясним, что собой представляют звуковые данные. Процесс цифровой записи звука можно абстрактно представить таким образом: под действием движения воздуха, в цепи микрофона возникают изменения силы тока, а компьютер с определенной частотой, именуемой частотой дискретизации, производит запись значения силы тока в относительных единицах от (в нашем случае от 0 до 255). Воспроизведение звука происходит в обратном порядке – с частотой дискретизации на звуковоспроизводящее устройство подается напряжение, сила которого зависит от значения, записанного в звуковом файле.
    Немного формальностей. WAV файла состоит из двух частей заголовка и области данных. Заголовок в нашем простейшем случае будет состоять из трех последовательно вложенных друг в друга заголовков (chunks). Первый — свойственный для файлов формата RIFF, представляет собой запись из трех полей: символов «RIFF», размера области данных в байтах (без учета размера самого заголовка), и второго «чунка».
    ExpandedWrap disabled
      tSoundFile=record
      Caption:array[0..3]of char;
      Size:longint;
      Data:tSoundFormat;
      end;

    Второй «чунк», элемент WAV-файлов, состоит из четырех частей:
    • слова «WAVE»,
    • слова «fmt »(три буквы и пробел в конце),
    • 32 битной переменной, хранящей размер следующего поля,
    • переменной типа tpcmWaveFormat, описанной в файле MMSystem.pas
    • третього „чунка”.
    ExpandedWrap disabled
      tSoundFormat=record
      Caption1,Caption2:array[0..3]of char;
      Size:longint;
      Format:tpcmWaveFormat;
      Data:tSoundData;
      end;

    тип tpcmWaveFormat представляет собой record из двух записей
    wf: TwaveFormat и wBitsPerSample: Word. Вторая указывает, сколько бит занимает одна выборка сигнала (в нашем случае 8). Первая – тип record, описывающий формат звуковых данных:
    ExpandedWrap disabled
      TWaveFormat = record
      wFormatTag: Word;
      nChannels: Word;
      nSamplesPerSec: Longint;
      nAvgBytesPerSec: longint;
      nBlockAlign: Word;
      end;

    wFormatTag – тип звуковых данных должен быть равен константе WAVE_FORMAT_PCM
    nChannels – количество каналов, для моно звука – 1.
    NsamplesPerSec — частота дискретизации.
    NavgBytesPerSec — количество байт передаваемое на воспроизведение в секунду.
    NblockAlign – размер одной выборки в байтах.

    Третий «чунк» тоже имеет тип record и содержит слово “data”, размер области данных и массив данных.

    ExpandedWrap disabled
      tSoundData=record
      Caption:array [0..3]of char;
      Size:longint;
      Data:array[0..0]of byte;
      end;


    В написании кода будем использовать следующие константы:
    FDiscretisation=44100; – частота дискретизации (рекомендуется брать только стандартеые значения: 8 000 Гц, 11 025 Гц, 12 000 Гц, 16 000 Гц, 22 050 Гц, 24 000 Гц, 32 000 Гц, 44 100 Гц, 48 000 Гц)
    Canals=1;– количесво каналов (у нас монозвук)
    Discret=8; – количество бит, занимаемых одной выборкой сигнала для одного канала

    Переменные:
    SoundFile:pSoundFile; – создадим наш файл сперва в динамической памяти.
    SizeOfData:longint; – размер массива данных
    SizeOfFile: longint; – размер файла.
    I: longint; – переменная-счетчик для цикла.

    По-е-ха-ли.
    Размер области данных у нас будет:
    ExpandedWrap disabled
      SizeOfData:=Duration*fDiscretisation*(Discret shr 3) div 1000;

    Размер файла – размер заголовка + длина массива данных-1 выборка.
    ExpandedWrap disabled
      SizeOfFile:=sizeOf(tSoundFile)+ SizeOfData-Discret shr 3;

    Выделяем память под файл:
    ExpandedWrap disabled
      GetMem(SoundFile,SizeOfFile);


    Заполняем заголовок
    ExpandedWrap disabled
      SoundFile^.Size:=SizeOfFile-SizeOf(SoundFile^.Caption)-SizeOf(SoundFile^.Size);
      SoundFile^.Data.Size:=SizeOf(tpcmWaveFormat);
      SoundFile^.Data.Data.Size:=SizeOfData;
       
      SoundFile^.Caption:='RIFF';
       
      SoundFile^.Data.Caption1:='WAVE';
      SoundFile^.Data.Caption2:='fmt ';
      SoundFile^.Data.Format.wBitsPerSample:=Discret;
      SoundFile^.Data.Format.wf.wFormatTag:=WAVE_FORMAT_PCM;
      SoundFile^.Data.Format.wf.nChannels:=Canals;
      SoundFile^.Data.Format.wf.nSamplesPerSec:=FDiscretisation;
      SoundFile^.Data.Format.wf.nAvgBytesPerSec:=FDiscretisation*Canals*(Discret shr 3);
      SoundFile^.Data.Format.wf.nBlockAlign:=(Canals*Discret)shr 3;
       
      SoundFile^.Data.Data.Caption:='data';


    Итак, с заголовком закончили и переходим к заполнению сегмента данных. Волна нашего звука на осциллографе имела бы прямоугольный вид, другими словами, один промежуток времени длительностью 1/n на звуковоспроизводящее устройство будет подаваться максимальный сигнал, а следующий равный по длительности промежуток нулевое напряжение.
    Итак, заполнение сегмента данных будим производить следующим образом: если конкретная выборка была бы сделана в четный промежуток времени 1/n, то оно равно 255, иначе оно равно 0:

    ExpandedWrap disabled
      for i:=0 to SoundFile^.Data.Data.Size-1 do
      if Round(Frequenz*i/fDiscretisation) mod 2=0 then
      SoundFile^.Data.Data.Data[i]:=255
      else
      SoundFile^.Data.Data.Data[i]:=0;


    Осталось лишь самым банальным образом переписать наш звуковой файл из динамической памяти в файл и освободить динамическую память.
    ExpandedWrap disabled
      Assign(F,FileName);
      ReWrite(F,1);
      BlockWrite(F,SoundFile^,SizeOfData);
      Close(F);
      FreeMem(SoundFile);


    Полный листинг выглядит так:
    ExpandedWrap disabled
      program BeepGenerator;
       
      {$R-}{$A-}
      const
      WAVE_FORMAT_PCM    = 1;
      type
      TWaveFormat = record
      wFormatTag: Word;
      nChannels: Word;
      nSamplesPerSec: Longint;
      nAvgBytesPerSec: longint;
      nBlockAlign: Word;
      end;
       
      TPCMWaveFormat=record
      wf: TWaveFormat;
      wBitsPerSample: Word;
      end;
       
      tSoundData=record
      Caption:array [0..3]of char;
      Size:longint;
      Data:array[0..0]of byte;
      end;
       
      tSoundFormat=record
      Caption1,Caption2:array[0..3]of char;
      Size:longint;
      Format:tpcmWaveFormat;
      Data:tSoundData;
      end;
       
      pSoundFile=^tSoundFile;
      tSoundFile=record
      Caption:array[0..3]of char;
      Size:longint;
      Data:tSoundFormat;
      end;
       
      const
      FDiscretisation=44100;
      Canals=1;
      Discret=8;
       
      procedure SaveBeep(FileName:string;Frequenz,Duration:integer);
      var
      F:File;
      SoundFile:pSoundFile;
      SizeOfData:longint;
      I: longint;
      SizeOfFile:longint;
      begin
      SizeOfData:=Duration*fDiscretisation*(Discret shr 3) div 1000;
      SizeOfFile:=sizeOf(tSoundFile)+ SizeOfData-Discret shr 3;
      GetMem(SoundFile,SizeOfFile);
       
      SoundFile^.Size:=SizeOfFile-SizeOf(SoundFile^.Caption)-SizeOf(SoundFile^.Size);
      SoundFile^.Data.Size:=SizeOf(tpcmWaveFormat);
      SoundFile^.Data.Data.Size:=SizeOfData;
       
      SoundFile^.Caption:='RIFF';
       
      SoundFile^.Data.Caption1:='WAVE';
      SoundFile^.Data.Caption2:='fmt ';
      SoundFile^.Data.Format.wBitsPerSample:=Discret;
      SoundFile^.Data.Format.wf.wFormatTag:=WAVE_FORMAT_PCM;
      SoundFile^.Data.Format.wf.nChannels:=Canals;
      SoundFile^.Data.Format.wf.nSamplesPerSec:=FDiscretisation;
      SoundFile^.Data.Format.wf.nAvgBytesPerSec:=FDiscretisation*Canals*(Discret shr 3);
      SoundFile^.Data.Format.wf.nBlockAlign:=(Canals*Discret)shr 3;
       
      SoundFile^.Data.Data.Caption:='data';
       
      Assign(F,FileName);
      ReWrite(F,1);
      for I:=0 to SoundFile^.Data.Data.Size-1 do
      if Round(Frequenz*i/fDiscretisation) mod 2=0 then
      SoundFile^.Data.Data.Data[i]:=255
      else
      SoundFile^.Data.Data.Data[i]:=0;
       
       
      BlockWrite(F,SoundFile^,SizeOfFile);
      FreeMem(SoundFile);
      Close(F);
      end;
       
      begin
      {Создадим файл Dash.wav, частотой 900 Гц и длительностью 0,75 с}
      SaveBeep('Dash.wav',900,750);
      end.
    Сообщение отредактировано: Jin X -
      Возможно, лучше бы область данных не размещать в динамическом массиве, а писать сразу в файл. Таким образом отпадет необходимость в пояснениие относительно динамических массивов и ограничение в размере файла для 16-битных систем.
        Эту статью стоит оформить по таким правилам:
        1. Вводная часть, состоящая из "истории" и цели статьи. Почему выбран тот или иной аспект.
        2. Теоретическая выкладка с формулами и ссылками на источники литературы и сайтов. Если неполно даётся материал, то давать пояснение откуда можно его взять и прочитать.
        3. Описание возможных трудностей и "подводных камней".
        4. Ядро статьи.
        5. Подведение итогов.
        6. Список источников (References).

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


          Рейтинг@Mail.ru
          [ Script execution time: 0,0670 ]   [ 15 queries used ]   [ Generated: 11.12.24, 01:04 GMT ]