Пробвам различни синусоидни помитания за да ги използвам в импулсни ривърби. Мисля, че ще е полезно да покажа кода в Java за създаването на един кратък файл уейв с едно синусоидно помитане. Кодът е прост, но е интересен. Интересен е не само защото създава едно синусоидно помитане, но защото и показва структурата на просите файлове уейв. За програмистите, които започват с DSP и искат да четат или пишат файлове уейв, може да е полезно.
Това не е най-елегантния код, но лесно се разбира.
Файлове с произволен достъп
Файловете с произволен достъп не са нужни в този малък код, но осъществяването на файлове уейв с произволен достъп е добра идея. Това позволява да прескачаме парчетата RIFF и уейв, от които не се нуждаем. Това също позволява да се местим напред и назад в данните с аудио в парчето данни във файла уейв, като при превъртането напред и назад.
Данните уейв
Данните във файловете уейв – данните за аудио и данните за формата – се запазват, като най-маловажния байт се записва пръв и най-важния байт се записва последен ("little endian"). Тъй като не можем да гарантираме, че всички операционни системи ще записват числата с правилния ред на байтовете, трябват ни функции, които да записват с правилния ред на байтовете.
По-точно, трябва да можем да записваме цели числа от четири байта и цели числа от два байта.
public static void writeInt(RandomAccessFile file, long value) throws IOException
{
long b0 = value & 0x000000ff;
long b1 = (value & 0x0000ff00) >> 8;
long b2 = (value & 0x00ff0000) >> 16;
long b3 = (value & 0xff000000) >> 24;
file.writeByte((byte) b0);
file.writeByte((byte) b1);
file.writeByte((byte) b2);
file.writeByte((byte) b3);
}
public static void writeShort(RandomAccessFile file, int value) throws IOException
{
int b0 = value & 0x000000ff;
int b1 = (value & 0x0000ff00) >> 8;
file.writeByte((byte) b0);
file.writeByte((byte) b1);
}
Синусоидно помитане
Кодът за създаването на синусоидното помитане е по-долу. Ето и стъпките.
- Създаваме едно синусоидно помитане, което помита честотите между 50 Hz и 1000 Hz в 1 секунда и слагаме резултата в един файл уейв с пробната честота 44.1 KHz и пробната резолюция 16 бита. Затова имаме и началните декларации.
- Започваме, като записваме идентификацията "RIFF" за файловете RIFF.
- След това записваме размера на файла RIFF. Размерът на файла RIFF включва: 1) 4 байта за под-идентификацията "WAVE"; 2) 4 байта за идентификацията "fmt "; 3) 4 байта за размера на парчето формат; 4) 16 байта за самото парче формат (размера на парчето формат е 16 байта, защото не броим размера на идентификацията и на размера на парчето формат); 5) 4 байта за идентификацията "data"; 6) samplingrate * channels * samplingresolution * T / 8 байта за данните за аудио.
- Записваме под-идентификацията "WAVE" за да отбележим, че този файл RIFF е файл WAVE.
- Записваме идентификацията на парчето формат.
- Записваме размера на парчето формат (без 4 байта за идентификацията и 4 байта за размера).
- Записваме различните части на парчето формат. Ще запазваме данни PCM и затова кода за компресиране е 1. Останалото е броя на каналите, пробната честота, средния брой на байтовете в секунда, размера на семплите за всички канали заедно ("block align") и броя на значителните бита в семплите (пробната резолюция).
- Записваме идентификацията на парчето данни.
- Записваме данните за аудио.
Тук има две синусоидни помитания – едно линейно (коментирано) и едно експоненциално.
Стойността на синусоидното помитане при всеки от семплите първо ще бъде между -1 и 1. Увеличаваме го до две трети от диапазона, позволен от записа с 16 бита (този избор от 2/3 е случаен и може да бъде променен). Когато записваме получените стойности, не използваме writeShort, защото writeShort по принцип е създадено да записва цели числа от два байта без знак, а пък данните за аудио имат знак (те са положителни или отрицателни).
Можеш да чуеш получените файлове уейв в темата в речника Синусоидно помитане.
try
{
float f0 = 50;
float f1 = 1000;
float T = 1;
float samplingrate = 44100F;
int samplingresolution = 16;
int channels = 1;
// open a wave file
RandomAccessFile file = new RandomAccessFile("chirp.wav", "rw");
// write the header
file.seek(0);
file.writeBytes("RIFF");
writeInt(file, (int) (4 + 4 + 4 + 16 + 4 + samplingrate * channels *
samplingresolution * T / 8));
file.writeBytes("WAVE");
// write the format chunk
file.writeBytes("fmt ");
writeInt(file, 16L); // size of format chunk
writeShort(file, 1); // format type
writeShort(file, channels);
writeInt(file, (int) samplingrate);
writeInt(file, ((int) samplingrate * channels * samplingresolution) / 8);
writeShort(file, (channels * samplingresolution) / 8);
writeShort(file, samplingresolution);
// write the data chunk
file.writeBytes("data");
writeInt(file, (int) (samplingrate * channels * samplingresolution * T / 8));
// write the sine sweep data
for(int i = 0; i < samplingrate; i++)
{
double t = (double) i / samplingrate;
//double value = Math.sin(2D * Math.PI
* (f0 * t + (f1 - f0) * t * t / (2 * T)));
double value = Math.sin(2D * Math.PI * f0 * T
* (Math.pow(f1 / f0, t / T) - 1) / (Math.log(f1 / f0)));
int ivalue = (int) Math.min(Math.max(value * Short.MAX_VALUE * 2 / 3,
Short.MIN_VALUE), Short.MAX_VALUE);
file.writeByte((byte) (ivalue & 0xff));
file.writeByte((byte) (ivalue >>> 8 & 0xff));
}
file.close();
}
catch (IOException e)
{
System.out.println("Exception: " + e);
}
автори: mic
Добави нов коментар