I am trying to record a 16khz mono-channel .wav file by using this code
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.TargetDataLine;
public class Main {
public static void main(String[] args) {
System.out.println("Say what you see..");
try {
AudioFormat format = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED, 16000, 8, 1, 4, 16000,
false);
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
if (!AudioSystem.isLineSupported(info))
System.out.println("Line not Supported");
final TargetDataLine targetLine = (TargetDataLine) AudioSystem
.getLine(info);
targetLine.open();
System.out.println("Recording");
targetLine.start();
Thread thread = new Thread() {
#Override
public void run() {
AudioInputStream audioStream = new AudioInputStream(
targetLine);
File audioFile = new File("record.wav");
try {
AudioSystem.write(audioStream,
AudioFileFormat.Type.WAVE, audioFile);
} catch (IOException ioe) {
ioe.printStackTrace();
}
System.out.println("stopped recording");
}
};
thread.start();
Thread.sleep(5000);
targetLine.stop();
targetLine.close();
System.out.println("Done");
} catch (Exception e) {
e.printStackTrace();
}
}
}
When I run it I always get this error:
Line not Supported
java.lang.IllegalArgumentException: No line matching interface TargetDataLine supporting format PCM_SIGNED 16000.0 Hz, 8 bit, mono, 4 bytes/frame, is supported.at javax.sound.sampled.AudioSystem.getLine(AudioSystem.java:476)at Main.main(Main.java:29)
ps: I tested it many times with different parameters for the AudioFormat It only worked when I tried these parameters which is stereo and 44.1khz
AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,44100,16,2,4,44100,false);
You must specify an AudioFormat that matches one of the formats supported by the TargetDataLine.
For example the microphone on my Mac supports:
'unknown sample rate' means the sample rate doesn't matter.
The main difference I see here is that you are specifying 4 bytes per frame, for 8 bit mono this should be 1 byte per frame.
Related
I'm making game extension to play some sounds. The sounds may be triggered at random times, which means that the same sound may be triggered twice with very little time apart. In this case, the sound should start playing even though it is already playing (if that makes sense).
I'm using a Clip to play the sound. This means that I have to "rewind" the clip before playing it. It seems, since it's the same clip, that it stops playing before re-starting. What I want is for it to continue playing, and play the same clip "on top" of the previos one. See this example:
import java.io.File;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
public class JavaApplication {
public static void main(String[] args) throws Exception {
File file = new File(JavaApplication.class.getResource("1.wav").getPath());
AudioInputStream inputStream = AudioSystem.getAudioInputStream(file);
Clip clip = AudioSystem.getClip();
clip.open(inputStream);
clip.setFramePosition(0);
clip.start(); // The sound is 300 ms long
Thread.sleep(150); // Let it play for 150 ms
clip.setFramePosition(0); // Attempt to start it from the beginning, without stopping it
clip.start();
Thread.sleep(1000);
}
}
Have you tried creating a duplicate object when you need it and destroy it when it's finished? A new Clip object or just copy the original and get it to play along with it.
Clip temp = clip;
temp.start(); // The sound is 300 ms long
Thread.sleep(150); // Let it play for 150 ms
temp = null;
Just a suggestion, you could also try using Clip[] arrays to handle a few clips playing at different times.
You need to create two AudioInputStream instances. No need to use multi thread exlicitly in your code. Hop it will help. Thanks.
import java.io.File;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
public class JavaApplication {
public static void main(String[] args) throws Exception {
File file = new File(JavaApplication.class.getResource("1.wav").getPath());
AudioInputStream inputStream1 = AudioSystem.getAudioInputStream(file);
AudioInputStream inputStream2 = AudioSystem.getAudioInputStream(file);
Clip clip = AudioSystem.getClip();
clip.open(inputStream1);
clip.setFramePosition(0);
clip.start();
// Clip is 2000 ms long. let it play for 1000 ms
Thread.sleep(1000);
Clip clip2 = AudioSystem.getClip();
clip2.open(inputStream2);
clip2.setFramePosition(0);
clip2.start();
Thread.sleep(2000);
}
}
Found a solution: Read the raw bytes of the sound, and create a inputstream from the data each time I play the sound. This enables me to play the same sound file "on top of itself" without loading it from disk more than once.
package com.mysite.javaapplication;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
public class JavaApplication {
private static void playSoundBytes(byte[] data) throws Exception {
AudioInputStream inputStream = AudioSystem.getAudioInputStream(new ByteArrayInputStream(data));
AudioFormat format = inputStream.getFormat();
Clip clip = AudioSystem.getClip();
clip.open(inputStream);
clip.setFramePosition(0);
clip.start();
}
private static byte[] getResourceAsBytes(String name, int bufferSize) throws IOException {
InputStream stream = JavaApplication.class.getResourceAsStream(name);
byte buffer[] = new byte[bufferSize];
int b, i = 0;
while ((b = stream.read()) != -1) {
try {
buffer[i++] = (byte) b;
} catch (IndexOutOfBoundsException e) {
throw new IOException("Buffer of " + bufferSize + " bytes is too small to read resource \"" + name + "\"");
}
}
byte data[] = new byte[i + 1];
while (i >= 0) {
data[i] = buffer[i];
i--;
}
return data;
}
public static void main(String[] args) throws Exception {
byte[] soundData = getResourceAsBytes("/1.wav", 1000*1000);
playSoundBytes(soundData);
Thread.sleep(1000);
playSoundBytes(soundData);
Thread.sleep(2000);
}
}
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.HashSet;
import java.util.Set;
public class RAFRead {
public static void main(String[] args) {
create();
read();
}
public static void create() {
// Create the set of options for appending to the file.
Set<OpenOption> options = new HashSet<OpenOption>();
options.add(StandardOpenOption.APPEND);
options.add(StandardOpenOption.CREATE);
// Create the custom permissions attribute.
Set<PosixFilePermission> perms = PosixFilePermissions
.fromString("rw-r-----");
FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions
.asFileAttribute(perms);
Path file = Paths.get("./outfile.log");
ByteBuffer buffer = ByteBuffer.allocate(4);
try {
SeekableByteChannel sbc = Files.newByteChannel(file, options, attr);
for (int i = 9; i >= 0; --i) {
sbc = sbc.position(i * 4);
buffer.clear();
buffer.put(new Integer(i).byteValue());
buffer.flip();
sbc.write(buffer);
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
public static void read() {
// Create the set of options for appending to the file.
Set<OpenOption> options = new HashSet<OpenOption>();
options.add(StandardOpenOption.READ);
Path file = Paths.get("./outfile.log");
ByteBuffer buffer = ByteBuffer.allocate(4);
try {
SeekableByteChannel sbc = Files.newByteChannel(file, options);
int nread;
do {
nread = sbc.read(buffer);
if(nread!= -1) {
buffer.flip();
System.out.println(buffer.getInt());
}
} while(nread != -1 && buffer.hasRemaining());
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
I first create the file.
I am trying to put 9, then 8, then 7 and so on in the file.
But I am trying to add to file in reverse order using random access.
The output of file actually will be numbers in ascending order.
I am just writing to file in reverse order to try out random access writing.
After that I try to read the file and print the data (numbers).
It prints only 0. I was expecting it to print 1-9.
I couldn't figure out the reason. Any help is appreciated.
I followed this link from Oracle site: https://docs.oracle.com/javase/tutorial/essential/io/file.html
The file has size after I run this program, so it seems program is writing.
Since it is buffer read, i can't see the data by vi or cat.
You need to flip() the buffer before calling write() or get()(and friends), and compact() afterwards.
I have two .3gp (or .wav) audio files that I have saved from the user's microphone. How can I concatenate these two audio files together in code into a single file? Thanks.
combining two wav files:
import java.io.File;
import java.io.IOException;
import java.io.SequenceInputStream;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
public class WavAppender {
public static void main(String[] args) {
String wavFile1 = "D:\\wav1.wav";
String wavFile2 = "D:\\wav2.wav";
try {
AudioInputStream clip1 = AudioSystem.getAudioInputStream(new File(wavFile1));
AudioInputStream clip2 = AudioSystem.getAudioInputStream(new File(wavFile2));
AudioInputStream appendedFiles =
new AudioInputStream(
new SequenceInputStream(clip1, clip2),
clip1.getFormat(),
clip1.getFrameLength() + clip2.getFrameLength());
AudioSystem.write(appendedFiles,
AudioFileFormat.Type.WAVE,
new File("D:\\wavAppended.wav"));
} catch (Exception e) {
e.printStackTrace();
}
}
}
Here is my code:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
public class EncryptedLogger {
private static Date lastLogTime = null;
private static EncryptedLogger instance = null;
private static FileOutputStream fos = null;
private static CipherOutputStream cos = null;
private static PrintWriter writer = null;
private Cipher cipher;
byte[] Key ={(byte) 0x12,(byte) 0x34,0x55,(byte) 0x66,0x67,(byte)0x88,(byte)0x90,0x12,(byte) 0x23,0x45,0x67,(byte)0x89,0x12,0x33,(byte) 0x55,0x74};
public static EncryptedLogger getInstance(){
if (instance==null) {
instance = new EncryptedLogger();
}
return instance;
}
private EncryptedLogger(){
class SQLShutdownHook extends Thread{
#Override
public void run() {
EncryptedLogger.close();
super.run();
}
}
SecretKeySpec sks = new SecretKeySpec(Key,"AES");
try {
cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE,sks);
fos = new FileOutputStream(new File("log.txt"),true);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
cos = new CipherOutputStream(fos, cipher);
writer = new PrintWriter(cos);
SQLShutdownHook hook = new SQLShutdownHook();
Runtime.getRuntime().addShutdownHook(hook);
}
public synchronized void logSQL(String s){
if ((lastLogTime==null)||((new Date().getTime() -lastLogTime.getTime())>1000)){
lastLogTime = new Date();
writer.printf("-- %1$tm-%1$te-%1$tY %1$tH-%1$tM-%1$tS\n%2$s\n",new Date(),s);
}
else{
writer.println(s);
}
}
public synchronized void logComment(String s){
writer.printf("-- %1$tm-%1$te-%1$tY %1$tH-%1$tM-%1$tS: %2$s\n",new Date(),s);
}
public static void close(){
writer.flush();
writer.close();
}
public static void main(String[] args) throws InterruptedException {
EncryptedLogger.getInstance().logSQL("1");
EncryptedLogger.getInstance().logSQL("22");
EncryptedLogger.getInstance().logSQL("33333");
EncryptedLogger.getInstance().logSQL("4900");
EncryptedLogger.getInstance().logSQL("5");
EncryptedLogger.getInstance().logSQL("66666");
EncryptedLogger.getInstance().logSQL("Some test logging statement");
EncryptedLogger.getInstance().logSQL("AAAAAAAAAAAAAAAAAAAAAAAAAA");
EncryptedLogger.getInstance().logComment("here is test commentary");
}
}
As you see i'm trying to encrypt text entries piping them through PrintWriter->CipherOutputStream->FileOutputStream chain. But when I decrypt result file there are missing bytes. I tried to flush cos and fos in EncryptedLogger.close() method - same result. Obviously i'm missing something. What is wrong?
EDIT: here is decryption code i use. It's not mine, taken from tutorial or something...
And it works fine when using simmilar encryption. But when using my code...
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class AESDecrypter
{
Cipher dcipher;
public AESDecrypter(SecretKey key)
{
try
{
dcipher = Cipher.getInstance("AES");
dcipher.init(Cipher.DECRYPT_MODE, key);
}
catch (Exception e)
{
e.printStackTrace();
}
}
byte[] buf = new byte[1024];
public void decrypt(InputStream in, OutputStream out)
{
System.out.println("decrypting");
try
{
in = new CipherInputStream(in, dcipher);
int numRead = 0;
while ((numRead = in.read(buf)) >= 0)
{
out.write(buf, 0, numRead);
}
out.close();
}
catch (java.io.IOException e)
{
}
}
public static void main(String args[])
{
try
{
byte[] keystr ={(byte) 0x12,(byte) 0x34,0x55,(byte) 0x66,0x67,(byte)0x88,(byte)0x90,0x12,(byte) 0x23,0x45,0x67,(byte)0x89,0x12,0x33,(byte) 0x55,0x74};
SecretKeySpec sks = new SecretKeySpec(keystr,"AES");
AESDecrypter encrypter = new AESDecrypter(sks);
encrypter.decrypt(new FileInputStream("sqllogenc.log"),new FileOutputStream("sqllogdec.log"));
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
EDIT2: when i write directly to fos i get this output:
-- 04-19-2012 16-17-56
1
22
33333
4900
5
66666 + delay starting 1100
Some test logging statement
AAAAAAAAAAAAAAAAAAAAAAAAAA
-- 04-19-2012 16-17-56: here is test commentary
and when writing using cos and decrypting:
-- 04-19-2012 16-22-13
1
22
33333
4900
5
66666 + delay starting 1100
Some test logging statement
AAAAAAAAAAAAAAAAAAAAAAAAAA
-- 04-19-2012 16-22-13: here
As you see part of the last line is missing including linebreak.
You should use the same cryptographic transformation (such as AES/ECB/NoPadding) at both sides. Also, note that NoPadding mode doesn't allow you to pass data of arbitrary size, therefore you need to specify some other kind of padding.
So, you need to construct Ciphers as Cipher.getInstance("AES/ECB/PKCS5Padding") at both sides.
Also, note the suggestion of rossum about use of CBC or CTR instead of ECB.
Well, AES has a fixed block size of 128 bits.
When you use AES/ECB/NoPadding, you take the responsability of making sure the size of your message is a multiple of the block size.
It probably isn't, so you get less text when you decrypt.
You should use AES/ECB/NoPadding for arbitrary length of text.
While playing an audio file (.wav) I want, if I resort to Ctrl+C, to stop the playback and save part of the audio file in a file called "file2.wav".
Here's the thread I'd like to add to my code.
Unfortunately it doesn't work at all.
class myThread extends Thread{
public void run(){
try {
PipedOutputStream poStream = new PipedOutputStream();
PipedInputStream piStream = new PipedInputStream();
poStream.connect(piStream);
File cutaudioFile = new File ("file2.wav");
AudioInputStream ais =
new AudioInputStream(piStream,
AudioFileFormat.Type.WAVE,
cutaudioFile);
poStream.write(ais,AudioFileFormat.Type.WAVE,cutaudioFile);
}catch (Exception e){
e.printStackTrace();
}
} // end run
} // end myThread
This should be basically what you want. It uses a shutdown hook.
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.sound.sampled.Clip;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class CtrlCAudio
{
public static void main(String[] args) throws LineUnavailableException, UnsupportedAudioFileException, IOException
{
final File inputAudio = new File(args[0]);
final File outputAudio = new File(args[1]);
// First, we get the format of the input file
final AudioFileFormat.Type fileType = AudioSystem.getAudioFileFormat(inputAudio).getType();
// Then, we get a clip for playing the audio.
final Clip c = AudioSystem.getClip();
// We get a stream for playing the input file.
AudioInputStream ais = AudioSystem.getAudioInputStream(inputAudio);
// We use the clip to open (but not start) the input stream
c.open(ais);
// We get the format of the audio codec (not the file format we got above)
final AudioFormat audioFormat = ais.getFormat();
// We add a shutdown hook, an anonymous inner class.
Runtime.getRuntime().addShutdownHook(new Thread()
{
public void run()
{
// We're now in the hook, which means the program is shutting down.
// You would need to use better exception handling in a production application.
try
{
// Stop the audio clip.
c.stop();
// Create a new input stream, with the duration set to the frame count we reached. Note that we use the previously determined audio format
AudioInputStream startStream = new AudioInputStream(new FileInputStream(inputAudio), audioFormat, c.getLongFramePosition());
// Write it out to the output file, using the same file type.
AudioSystem.write(startStream, fileType, outputAudio);
}
catch(IOException e)
{
e.printStackTrace();
}
}
});
// After setting up the hook, we start the clip.
c.start();
}
}