2014-09-07 15 views
0

나는 문제가 있으며 여기에 답변을 얻으려고합니다. 애플릿에서 작동해야하기 때문에 클라이언트 PC에 저장하지 않고 많은 미디 사운드를 만들고 싶습니다. 사운드 파트를 만드는 것이 문제는 아니지만 문제는이 사운드를 동시에 재생하는 것입니다. 나는 지금 asnwer를 위해 3 일 이상을 조사했다. 그러나 나를 도왔던 하나를 발견 할 수 없었다.Java에서 동시에 생성 된 MIDI 사운드 재생

:

import java.io.*; 
import javax.sound.sampled.*; 
import java.net.URL; 
import javax.sound.*; 

public class Sound { 

    /** 
    * The sample rate - 44,100 Hz for CD quality audio. 
    */ 
    public static int channels = 2; 




    public static final int SAMPLE_RATE = 44100; 

    private static final int BYTES_PER_SAMPLE = 4;    // 16-bit audio 
    private static final int BITS_PER_SAMPLE = 16;    // 16-bit audio 
    private static final double MAX_16_BIT = Short.MAX_VALUE;  // 32,767 
    private static final int SAMPLE_BUFFER_SIZE = 4096; 


    static SourceDataLine[] line = new SourceDataLine[channels]; // to play the   sound 
    private static byte[][] buffer = new byte[2][];   // our internal buffer 
    private static int i = 0;    // number of samples currently in internal buffer 
    private static int i2 = 0; 

    public static Mixer mainmix; 

    // static initializer 
    public Sound() 
    { 
     init(); 
    } 

    // open up an audio stram 
    static void init() { 
     try { 

      Mixer.Info[] mixerinfo = AudioSystem.getMixerInfo();  

      mainmix = AudioSystem.getMixer(mixerinfo[0]); 

      Line.Info lineinf[] = mainmix.getSourceLineInfo(); 

      // 44,100 samples per second, 16-bit audio, mono, signed PCM, little Endian 
      AudioFormat format = new AudioFormat((float) SAMPLE_RATE, BITS_PER_SAMPLE, 2, true, false); 
      DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); 


      line[0] = (SourceDataLine) mainmix.getLine(info); 
      line[1] = (SourceDataLine) mainmix.getLine(info); 
      //line[2] = (SourceDataLine) mainmix.getLine(info); 

      Control[] linectrl = line[0].getControls(); 
      Control[] linectrl1 = line[1].getControls(); 



      //line = (SourceDataLine) AudioSystem.getLine(info); 
      line[0].open(format, SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE); 
      line[1].open(format, SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE); 
      // line[2].open(format, SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE); 
      //line[1].open(format, SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE); 



      // the internal buffer is a fraction of the actual buffer size, this choice is arbitrary 
      // it gets diveded because we can't expect the buffered data to line up exactly with when 
      // the sound card decides to push out its samples. 
      buffer[0] = new byte[SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE]; 
      buffer[1] = new byte[SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE]; 
      //buffer[2] = new byte[SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE]; 
     } catch (Exception e) { 
      System.out.println(e.getMessage()); 
      System.exit(1); 
    } 


     // no sound gets made before this call 
     line[0].flush(); 
     line[0].start(); 
     line[1].flush(); 
     line[1].start(); 
} 

    /** 
    * Close standard audio. 
    */ 
    public final void close() { 
     line[0].drain(); 
     line[0].stop(); 

     line[1].drain(); 
     line[1].stop();   
    } 

    public final void play(double in) { 

     // clip if outside [-1, +1] 
     if (in < -1.0) in = -1.0; 
     if (in > +1.0) in = +1.0; 

     // convert to bytes 
     short s = (short) (MAX_16_BIT * in); 
     buffer[0][i++] = (byte) s; 
     buffer[0][i++] = (byte) (s >> 8); // little Endian 
     buffer[0][i++] = (byte) s; 
     buffer[0][i++] = (byte) (s >> 8); // little Endian 


     // send to sound card if buffer is full   
     if (i >= buffer.length) { 
      line[0].write(buffer[0], 0, 4); 

      i = 0; 
     } 
    } 

    public void play(double[] input) { 
     for (int i = 0; i < input.length; i++) { 
      play(input[i]); 

     } 
    } 

    public final void play(double in, double an) { 


     // clip if outside [-1, +1] 
     if (in < -1.0) in = -1.0; 
     if (in > +1.0) in = +1.0; 

     // convert to bytes 
     short s = (short) (MAX_16_BIT * in); 
     buffer[1][i++] = (byte) s; 
     buffer[1][i++] = (byte) (s >> 8); // little Endian 
     buffer[1][i++] = (byte) s; 
     buffer[1][i++] = (byte) (s >> 8); // little Endian 

     // clip if outside [-1, +1] 
     if (an < -1.0) an = -1.0; 
     if (an > +1.0) an = +1.0; 

     // convert to bytes 
     short a = (short) (MAX_16_BIT * an); 
     buffer[0][i2++] = (byte) a; 
     buffer[0][i2++] = (byte) (a >> 8); // little Endian 
     buffer[0][i2++] = (byte) a; 
     buffer[0][i2++] = (byte) (a >> 8); // little Endian 

     // send to sound card if buffer is full   
     if (i >= buffer.length) { 

      line[1].write(buffer[1], 0, 4); 
      line[0].write(buffer[0], 0, 4); 


      i2 = 0; 
      i = 0; 
     } 
    } 

public void play(double[] input,double[] input1) { 
     for (int i = 0; i < input.length; i++) { 
      play(input[i],input1[i]); 

     } 
    } 
} 

이 내가 내 소리를 만들 수있는 곳입니다 :

내 사운드 (오픈 spurce 프로젝트에서 그것의 발견 부분) : 여기

내가 지금 무엇을 가지고 여기
public class Note { 
    private final int SAMPLE_RATE = 44100; 
    private double[] tone; 
    public Note(double hz, double duration, double amplitude) 
    { 
     int N = (int) Math.round(SAMPLE_RATE * duration); 
     tone = new double[N+1]; 
     for (int i = 0; i <= N; i++) 
      tone[i] = amplitude * Math.sin(2 * Math.PI * i * hz/SAMPLE_RATE); 
    } 

    public double[] getTone() 
    { 
     return tone; 
    } 

} 

내 임시 Main 클래스 : 공용 클래스 테스트 {

public static void main(String[] args) { 
     Sound sound = new Sound(); 

     //Note(hz (freg),seconds (duration),vol(amplitude)) 
     Note note1 = new Note(50.0,3.0,6); 
     Note note2 = new Note(10.0,3.0,6); 
     sound.play(note1.getTone(),note2.getTone()); 
    } 

} 

스레드에 대해 생각했지만 20-30 ++ 스레드가 있다면 생각하지 않습니다. 동시에 쓰지 않을 것이고 성능은 그렇게 좋지 않을 것입니다. 나는 그들이 동시에 소리를내는 예를 보았지만 파일에서 사운드를로드했고, 미디로 시도했을 때 작동하지 않았다.

답변

0

타임 스탬프를 사용하는 곳이 표시되지 않습니다. MIDI를 사용하면 일반적으로 즉시 재생하거나 주어진 순간에 재생할 수 있도록 사운드를 예약 할 수 있습니다. MIDI에서 동시 사운드를 재생하는 것 같아요. 일반적으로 같은 시간 또는 타임 스탬프로 모든 이벤트를 예약하는 것입니다. 이 다루는

튜토리얼 부분은 여기에 있습니다 : http://docs.oracle.com/javase/tutorial/sound/MIDI-messages.html

당신은 당신의 자신의 재생 코드를 작성 했습니까? 주어진 시점에 재생하도록 수정 할 수 있습니까?

또한 자신의 소리를 직접 쓰려면 소리를 함께 사용해야합니다. 이는 대부분 PCM 형식 인 각 재생 이벤트의 데이터를 추가하는 것입니다. 귀하의 코드에서 어디에서이 작업을 수행 할 수 있는지 또는해야 하는지를 파악할 시간이 없으니 용서하십시오. 다음은 필요한 단계를 간략하게 요약 한 것입니다. 주어진 순간에 예정된 각 이벤트를 반복하는 while 루프를 만든 다음 바이트 스트림을 각 프레임의 PCM 데이터로 어셈블하고 동시에 재생중인 프레임을 합칩니다 (왼쪽 채널 데이터는 왼쪽, 오른쪽 채널 데이터를 오른쪽으로) 변환 한 다음 PCM 값을 SourceDataLine에 필요한 형식의 바이트로 다시 역 어셈블합니다.