2015-10-31 4 views
0

У меня есть класс, который воспроизводит чистый синус тон с любой желаемой частотой и длиной, и он работает как ожидалось - за исключением небольшого выскакивающего звука из динамиков, который возникает в начале и в конце каждого тона , Сначала это был эксперимент по теории музыки, но я недавно использовал его, чтобы воспроизвести фрагменты песен и даже попытаться связать частоты с клавиатурой и сделать ее инструментом. Проблема в том, что попсы возникают между каждым тоном, что делает фразу звучать неправильно.Popping sound with SourceDataLine audio

Вот источник:

import java.util.*; 
import javax.sound.sampled.*; 

public class Tone { 
    public static float SAMPLE_RATE = 44100; 

    public static void sound(double frequency, int duration, double velocity) 
    throws LineUnavailableException { 
     if (frequency < 0) 
      throw new IllegalArgumentException("Frequency too low: " + frequency + " is less than 0.0"); 

     if (duration <= 0) 
      throw new IllegalArgumentException("Duration too low: " + duration + " is less than or equal to 0"); 

     if (velocity > 1.0 || velocity < 0.0) 
      throw new IllegalArgumentException("Velocity out of range: " + velocity + " is less than 0.0 or greater than 1.0"); 

     byte[] wave = new byte[(int)SAMPLE_RATE * duration/1000]; 

     for (int i=0; i<wave.length; i++) { 
      double angle = i/(SAMPLE_RATE/frequency) * 2.0 * Math.PI; 
      wave[i] = (byte)(Math.sin(angle) * 127.0 * velocity); 
     } 

     // Shape Waveform 
     for (int i=0; i < SAMPLE_RATE/100.0 && i < wave.length/2; i++) { 
      wave[i] = (byte)(wave[i] * i/(SAMPLE_RATE/100.0)); 
      wave[wave.length-1-i] = 
      (byte)(wave[wave.length-1-i] * i/(SAMPLE_RATE/100.0)); 
     } 

     AudioFormat af = new AudioFormat(SAMPLE_RATE, 8, 1, true, false); 
     SourceDataLine sdl = AudioSystem.getSourceDataLine(af); 
     sdl.open(af); 
     sdl.start(); 
     sdl.write(wave, 0, wave.length); 
     sdl.drain(); 
     sdl.close(); 
    } 

    public static double HALF_STEP = 1.0595; 
    public static double WHOLE_STEP = HALF_STEP * HALF_STEP; 
    public static double OCTAL_STEP = 2; 

    public static double oct(double octive){ 
     if (octive < 3) 
      throw new IllegalArgumentException("Octive too low: " + octive + " is less than 3.0"); 

     octive = octive - 2; 
     octive = Math.pow(OCTAL_STEP, octive); 

     return octive; 

    } 

    public static void main(String[] args) throws 
    LineUnavailableException { 
     // Preset Frequencies in Concert Notation starting from Octive 3 
     double rest = 0; 
     double c = 130.81; 
     double c$ = c * HALF_STEP; 
     double d = c$ * HALF_STEP; 
     double d$ = d * HALF_STEP; 
     double e = d$ * HALF_STEP; 
     double f = e * HALF_STEP; 
     double f$ = f * HALF_STEP; 
     double g = f$ * HALF_STEP; 
     double g$ = g * HALF_STEP; 
     double a = g$ * HALF_STEP; 
     double a$ = a * HALF_STEP; 
     double b = a$ * HALF_STEP; 

     // Default BPM 
     int bpm = 128; 

     // Note Duration Calculations 
     int whole = 1000 * 240/bpm; 
     int half = 1000 * 120/bpm; 
     int quarter = 1000 * 60/bpm; 
     int eighth = 1000 * 30/bpm; 
     int sixteenth = 1000 * 15/bpm; 
     int thirtysecond = 1000 * 7/bpm; 

     // Test Tones 
     Tone.sound (c * oct(3), sixteenth, 0.5); 
     Tone.sound (c$ * oct(3), sixteenth, 0.5); 
     Tone.sound (d * oct(3), sixteenth, 0.5); 
     Tone.sound (d$ * oct(3), sixteenth, 0.5); 
     Tone.sound (e * oct(3), sixteenth, 0.5); 
     Tone.sound (f * oct(3), sixteenth, 0.5); 
     Tone.sound (f$ * oct(3), sixteenth, 0.5); 
     Tone.sound (g * oct(3), sixteenth, 0.5); 
     Tone.sound (g$ * oct(3), sixteenth, 0.5); 
     Tone.sound (a * oct(3), sixteenth, 0.5); 
     Tone.sound (a$ * oct(3), sixteenth, 0.5); 
     Tone.sound (b * oct(3), sixteenth, 0.5); 
     Tone.sound (c * oct(4), sixteenth, 0.5); 
     Tone.sound (c$ * oct(4), sixteenth, 0.5); 
     Tone.sound (d * oct(4), sixteenth, 0.5); 
     Tone.sound (d$ * oct(4), sixteenth, 0.5); 
     Tone.sound (e * oct(4), sixteenth, 0.5); 
     Tone.sound (f * oct(4), sixteenth, 0.5); 
     Tone.sound (f$ * oct(4), sixteenth, 0.5); 

     // John Cena, Doot Doot Doot 
     Tone.sound(g * oct(4), eighth, 0.5); 
     Tone.sound(a * oct(4), sixteenth, 0.5); 
     Tone.sound(f * oct(4), sixteenth, 0.5); 
     Tone.sound(rest, thirtysecond, 0); 
     Tone.sound(g * oct(4), eighth + half, 0.5); 

     Tone.sound(rest, eighth, 0); 
     Tone.sound(a$ * oct(4), eighth, 0.5); 
     Tone.sound(a * oct(4), sixteenth, 0.5); 
     Tone.sound(f * oct(4), sixteenth, 0.5); 
     Tone.sound(rest, thirtysecond, 0); 
     Tone.sound(g * oct(4), eighth + half, 0.5); 

     Tone.sound(rest, eighth, 0); 
     Tone.sound(g * oct(4), eighth, 0.5); 
     Tone.sound(a * oct(4), sixteenth, 0.5); 
     Tone.sound(f * oct(4), sixteenth, 0.5); 
     Tone.sound(rest, thirtysecond, 0); 
     Tone.sound(g * oct(4), eighth + half, 0.5); 

     Tone.sound(rest, eighth, 0); 
     Tone.sound(a$ * oct(4), eighth, 0.5); 
     Tone.sound(a * oct(4), sixteenth, 0.5); 
     Tone.sound(f * oct(4), sixteenth, 0.5); 
     Tone.sound(rest, thirtysecond, 0); 
     Tone.sound(g * oct(4), eighth + half, 0.5); 
    } 
} 

Примечание: Я действительно новичок в Java, и я уверен, что мой стиль все виды перепутались. Не стесняйтесь критиковать или изменять это, пока вы здесь.

ответ

1

То, что вы слышите, является результатом разрыва от 0 до полной громкости. Чтобы устранить поп, вам необходимо постепенно начинать или останавливать тон.

Простым способом сделать это будет создание коэффициента громкости и увеличение его от 0 до 1 в течение первого и/или последнего звуковых кадров вашего аудио-образца. Вы должны поэкспериментировать, чтобы определить точное количество необходимых кадров. Я бы попробовал что-то вроде 64 кадров. Вы всегда можете увеличить эту цифру, если попсы все еще присутствуют, а меньшие также могут работать нормально.

Может быть что-то вроде этого:

int rampFrames = 64; 

for (int i = 0; i < rampFrames; i++) 
{ 
    wave[i] *= i/(float)rampFrames; 
} 

Нечто подобное можно сделать для выпусков. И, что-то подобное, вероятно, нужно будет делать, когда вы меняете громкость тона, если во время перехода есть поп.

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