2016-10-24 10 views
1

次のコードは、正弦波を含むFileを作成する必要があります。典型的な周波数(220Hz、440Hz、880Hz)ではそれは大きくなりますが、他の多くの周波数では、225Hz、883Hzなどとは異なります。任意の周波数に対して正弦波を得るにはどうすればよいですか?正弦波とユーザー定義の持続時間と周波数で.wavファイルを生成する方法はありますか?

import java.lang.Math; 
import java.io.File; 
import java.io.IOException; 
import java.io.RandomAccessFile; 

public class CreateSine 
{ 
    static String fileNameString = "Sine.wav"; 

    static File file = new File(fileNameString); 
    static String filePath = file.getAbsolutePath(); 

    static RandomAccessFile raw; 

    static int byteCount = 0; 
    static double pow215 = Math.pow(2, 15); 

    static float freq = 440.0f; 
    static int sRate = 44100; 
    static int bitDepth = 16; 
    static int nChannels = 1; 
    static int dur = 1; 

    static float changeRate = (float)((2.0 * Math.PI * freq)/sRate); 

    public static void main(String[] args) 
    { 
     try 
     { 
      raw = new RandomAccessFile(filePath, "rw"); 

      raw.setLength(0); // Set file length to 0, to prevent unexpected behavior in case the file already existed 
      raw.writeBytes("RIFF"); 
      raw.writeInt(0); // Final file size not known yet, write 0. This is = sample count + 36 bytes from header. 
      raw.writeBytes("WAVE"); 
      raw.writeBytes("fmt "); 
      raw.writeInt(Integer.reverseBytes(16)); // Sub-chunk size, 16 for PCM 
      raw.writeShort(Short.reverseBytes((short) 1)); // AudioFormat, 1 for PCM 
      raw.writeShort(Short.reverseBytes((short)nChannels));// Number of channels, 1 for mono, 2 for stereo 
      raw.writeInt(Integer.reverseBytes(sRate)); // Sample rate 
      raw.writeInt(Integer.reverseBytes(sRate*bitDepth*nChannels/8)); // Byte rate, SampleRate*NumberOfChannels*bitDepth/8 
      raw.writeShort(Short.reverseBytes((short)(nChannels*bitDepth/8))); // Block align, NumberOfChannels*bitDepth/8 
      raw.writeShort(Short.reverseBytes((short)bitDepth)); // Bit Depth 
      raw.writeBytes("data"); 
      raw.writeInt(0); // Data chunk size not known yet, write 0. This is = sample count. 
     } 
     catch(IOException e) 
     { 
      System.out.println("I/O exception occured while writing data"); 
     } 

     for (int i = 0; i < sRate*dur; i++) 
     { 
      writeSample((float)Math.sin(i * changeRate)); 
     } 

     closeFile(); 
     System.out.print("Finished"); 
    } 

    static void writeSample(float floatValue) 
    { 
     try 
     { 
      short hexSample = (short)((floatValue * pow215)); 
      raw.writeShort(Short.reverseBytes(hexSample)); 
      byteCount += 2; 
     } 
     catch(IOException e) 
     { 
      System.out.println("I/O exception occured while writing data"); 
     } 
    } 

    static void closeFile() 
    { 
     try 
     { 
      raw.seek(4); // Write size to RIFF header 
      raw.writeInt(Integer.reverseBytes(byteCount + 36)); 
      raw.seek(40); // Write size to Subchunk2Size field 
      raw.writeInt(Integer.reverseBytes(byteCount)); 
      raw.close(); 
     } 
     catch(IOException e) 
     { 
      System.out.println("I/O exception occured while closing output file"); 
     } 
    } 
} 

ありがとうございました。

答えて

0

あなたの質問には、それがいいとは言えないということ以外は何の問題もありません。私は浮動小数点から整数への変換でクリッピングが発生していると推測する危険があります。

  • sin関数が出力できる最大値は1.0です。
  • あなたは2^15、または32768
  • 最大の正の符号付きshortによって出力を使用すると、異なる周波数でクリッピング経験している理由は、正弦関数だけで1.0に当たるということである32767

される乗算しますsin(1+4k*pi/2)であり、kは任意の正の整数である。特定の周波数(例えば441Hz)は1.0に非常によくぶつかり、他の周波数はそうではない。

浮動小数点数を掛けるのは、((2^15)-1)

です。
0

各floatにfloat * float * 2 * 15を掛け合わせる代わりに、修正されたコードは以下のようになります:float * 0x7FFF、jaketの指摘どおりfloat *((2^15)-1 ):

import java.lang.Math; 
import java.io.File; 
import java.io.IOException; 
import java.io.RandomAccessFile; 

public class CreateSine 
{ 
    static String fileNameString; 
    static File file; 
    static String filePath; 

    static RandomAccessFile raw; 

    static int byteCount = 0; 

    static float freq; 
    static int sRate = 44100; 
    static int bitDepth = 16; 
    static int nChannels = 1; 
    static int dur; 

    static float changeRate; 

    public static void main(String[] args) 
    { 
     freq = Float.parseFloat(args[0]); 
     changeRate = (float)((2.0 * Math.PI * freq)/sRate); 

     dur = Integer.parseInt(args[1]); 

     fileNameString = (String)args[2] + ".wav"; 
     file = new File(fileNameString); 
     filePath = file.getAbsolutePath(); 

     try 
     { 
      raw = new RandomAccessFile(filePath, "rw"); 

      raw.setLength(0); // Set file length to 0, to prevent unexpected behavior in case the file already existed 
      raw.writeBytes("RIFF"); 
      raw.writeInt(0); // Final file size not known yet, write 0. This is = sample count + 36 bytes from header. 
      raw.writeBytes("WAVE"); 
      raw.writeBytes("fmt "); 
      raw.writeInt(Integer.reverseBytes(16)); // Sub-chunk size, 16 for PCM 
      raw.writeShort(Short.reverseBytes((short) 1)); // AudioFormat, 1 for PCM 
      raw.writeShort(Short.reverseBytes((short)nChannels));// Number of channels, 1 for mono, 2 for stereo 
      raw.writeInt(Integer.reverseBytes(sRate)); // Sample rate 
      raw.writeInt(Integer.reverseBytes(sRate*bitDepth*nChannels/8)); // Byte rate, SampleRate*NumberOfChannels*bitDepth/8 
      raw.writeShort(Short.reverseBytes((short)(nChannels*bitDepth/8))); // Block align, NumberOfChannels*bitDepth/8 
      raw.writeShort(Short.reverseBytes((short)bitDepth)); // Bit Depth 
      raw.writeBytes("data"); 
      raw.writeInt(0); // Data chunk size not known yet, write 0. This is = sample count. 
     } 
     catch(IOException e) 
     { 
      System.out.println("I/O exception occured while writing data"); 
     } 

     for (int i = 0; i < sRate*dur; i++) 
     { 
      writeSample((float)Math.sin(i * changeRate)); 
     } 

     closeFile(); 
     System.out.print("Finished"); 
    } 

    static void writeSample(float floatValue) 
    { 
     try 
     { 
      char shortSample = (char)((floatValue)*0x7FFF); 
      raw.writeShort(Character.reverseBytes(shortSample)); 
      byteCount += 2; 
     } 
     catch(IOException e) 
     { 
      System.out.println("I/O exception occured while writing data"); 
     } 
    } 

    static void closeFile() 
    { 
     try 
     { 
      raw.seek(4); // Write size to RIFF header 
      raw.writeInt(Integer.reverseBytes(byteCount + 36)); 
      raw.seek(40); // Write size to Subchunk2Size field 
      raw.writeInt(Integer.reverseBytes(byteCount)); 
      raw.close(); 
     } 
     catch(IOException e) 
     { 
      System.out.println("I/O exception occured while closing output file"); 
     } 
    } 
} 
関連する問題