I'm using the javax.sound.sampled package in a radio data mode decoding program. To use the program the user feeds audio from their radio receiver into their PC's line input. The user is also required to use their mixer program to select the line in as the recording input. The trouble is some users don't know how to do this and also sometimes other programs alter the recording input setting. So my question is how can my program detect if the line in is set as the recording input ? Also is it possible for my program to change the recording input setting if it detects it is incorrect ?
Thanks for your time.
Ian
To answer your first question, you can check if the Line.Info object for your recording input matches Port.Info.LINE_IN like this:
public static boolean isLineIn(Line.Info lineInfo) {
Line.Info[] detected = AudioSystem.getSourceLineInfo(Port.Info.LINE_IN);
for (Line.Info lineIn : detected) {
if (lineIn.matches(lineInfo)) {
return true;
}
}
return false;
}
However, this doesn't work with operating systems or soundcard driver APIs that don't provide the type of each available mixer channel. So when I test it on Windows it works, but not on Linux or Mac. For more information and recommendations, see this FAQ.
Regarding your second question, you can try changing the recording input settings through a Control class. In particular, see FloatControl.Type for some common settings. Keep in mind that the availability of these controls depends on the operating system and soundcard drivers, just like line-in detection.
Related
I am trying to perform a simple task, select an input device and set the output device.
The use case is as follows, I have 3.5mm jacks and my user can select the output device (headphones or speaker) from a list.
I can play a sound on a given device (with clip), I can control the input device (mute/volume), but I haven't found any way to specify the target line, it's always the system default.
I can get the mixer
Optional<Mixer.Info> optJackInMixerInfo = Arrays.stream(AudioSystem.getMixerInfo())
.filter(mixerInfo -> {
// Filter based on the device name.
})
.findFirst();
Mixer m = AudioSystem.getMixer(jackInMixerInfo);
// The target
Line.Info[] lineInfos = m.getTargetLineInfo();
for (Line.Info lineInfo : lineInfos) {
m.getLine(lineInfo);
System.out.println("ici");
}
I got only the "master volume control".
How can I select the output device ? I can be happy with changing the system default device too.
The naming of TargetDataLine and SourceDataLine is kind of backwards. Outputs to the local sound system for playback are directed to a SourceDataLine and inputs to Java like microphone lines use TargetDataLine. I used to know why they were named this way but it's slipped my mind at the moment.
There is a tutorial Accessing Audio System Resources with specifics.
Most computers only have a limited number of float controls available, with "master volume" being the one most likely to be implemented. You would use this to alter the volume of the output. Another tutorial in the series, Processing Audio with Controls covers this topic. For myself, I generally convert the audio stream to PCM and handle volume directly (multiply each value by a factor that ranges from 0 to 1) and then convert back to a byte stream, rather than rely on controls which may or may not be present.
A MIDI channel administers parameters such as sound, panning, volume etc.; thus for ensemble music, each of its real instrument should be represented by a channel of its own. If more than 15 non-percussion instruments are involved, a single MIDI line is not enough.
The Java software I write is intended for users most of whom will use the Java built-in software synthesizer. I want to allow for more than 16 instruments. Given the existing API as far as I know it, I need several MidiReceiver objects that work independently.
First try: the soft synthesizer asserts "getMaxReceivers() == -1", i.e. unlimited, so I create as many as I need. Unfortunately, they all use the same channels – failure.
Second try: I create two MidiDevice objects for the same Info object, and a MidiReceiver for each. When I try to open the second one, I get an exception saying that no further audio line is available.
Third try: Same as second, but for opening the devices, I use a special method of the SoftSynthesizer class that allows me to open it with a given audio line; I do so using the same line. No exception thrown – but chaotic audio output. Since the two objects don't know about each other, they cannot add their output gracefully. Failure again.
Questions:
A) Have I overlooked something?
B) If not, would someone who has the contacts and reputation please alarm the authors of the Java interface and the SoftSynthesizer? My proposal, minimally invasive: A (Soft)Synthesizer object should be endowed with an additional method such as "MidiDevice getSubdevice()", on which getReceiver() offers fresh channels as required.
(Upon re-editing: Could it be that the ordinary getReceiver() method is actually meant for this purpose, as described in my "First try" above, and has simply been misimplemented by the SoftSynthesizer "Gervill"? If so, Gervill should be informed, who, however, is not easy to find by googling. You may know how to contact him/her/them.)
public boolean GetTwoIndependenttReceivers (Receiver [] inhereplease)
{
for (MidiDevice.Info info : MidiSystem.getMidiDeviceInfo ()) try
{
MidiDevice device = MidiSystem.getMidiDevice (info);
if ( device instanceof Synthesizer
&& ( device.getMaxReceivers () < 0
|| device.getMaxReceivers () >= 2)) try
{
device.open ();
inhereplease [0] = device.getReceiver ();
inhereplease [1] = device.getReceiver ();
// will be distinct as objects, but with Gervill not independent
return true;
} catch (Exception ex) {}
} catch (Exception ex) {}
return false;
}
Note that, for example, the free software MuseScore manages the problem all right with its own software synthesizer. It exports MIDI files with "MIDI port" MIDI messages, as intended by the MIDI standard for exactly that purpose, and imports them gracefully. The built-in Java sequencer simply ignores those port messages and therefore plays the files incorrectly. This may be an additional incentive to attack the problem: one Receiver object for each port.
The MIDI standard only supports 16 channels. Full stop.
So, anything you want to do to control more channels than that goes outside the normal MIDI specification. The regular Windows GM synthesizer supports what it supports and isn't going to change. If you need additional capabilities, you'll have to use a different synthesizer, inside your application.
Is there a way to clear the console when the Java program detects the user it's introducing some data?
I'm executing a program that does the following:
User: //enter username
//show data of the username
I want to make it so the user can search for as many users he want until he ends the execution.
To make it clear and nice, after each username search, I want to clear the screen when the program detects the user is typing something (filling the buffer).
Is there any way to do this?
This is the code I'm using to clear the console (this does not detect when the user is typing):
public static void clearScreen() {
System.out.print("\033[H\033[2J");
System.out.flush();
}
Thanks in advance.
You cannot use System.in without pressing the ENTER key at the end. Its the only way. System.in is not aware of the user input until enter is pressed. So if you are using a normal command line to do this, this won't work and you have to stick different raw command lines like jline
For example :
Terminal terminal = TerminalBuilder.builder().system(true).jna(true).build();
terminal.enterRawMode(); //this enters into a raw mode and get's input on reader
reader = terminal.reader();
//finally
reader.close();
You can check it out. Although it highly doesn't make sense to bring in more dependencies unless you really want to and could just stick to a simple while loop
If you are using maven here's the dependency you can use.
<dependency>
<groupId>org.jline</groupId>
<artifactId>jline</artifactId>
</dependency>
By default, a terminal can only output text line by line.
Moving the cursor around, changing colors or clearing the screen requires special escape sequences that are interpreted by the terminal emulator in which you run your application.
C programs in Linux would usually do this via the ncurses library.
Java programs can do something similar with Lanterna (https://github.com/mabe02/lanterna) but within a GUI window. See also this article, which names other alternatives and shows how to use Lanterna: http://rememberjava.com/cli/2017/01/22/ncurses_terminal_libs.html
Is there any way to detect system sound instead of microphone sound? I want to be able to detect whenever my system makes a sound instead of when the microphone picks up the actual sound.
One way I found to do this use an "audio loop-back in either software or hardware (e.g. connect a lead from the speaker 'out' jack to the microphone 'in' jack)."
Capturing speaker output in Java
I am building a program that plays an mp3 file whenever a system sound happens but I don't want it to go off if the dog barks.
Thanks!
What about something with pyaudio (http://people.csail.mit.edu/hubert/pyaudio/)
Like this:
import pyaudio
chunk = 1024
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paInt16,
channels=1,
rate=44100,
input=True,
frames_per_buffer=chunk)
data = stream.read(chunk)
And then you could calculate the root-mean-square(RMS) of the audio sample and go from there.
Edited:
You can see what kind of devices you can use by doing something like the following. (http://people.csail.mit.edu/hubert/pyaudio/docs/#pyaudio.PyAudio.get_device_info_by_index)
import pyaudio
p = pyaudio.PyAudio()
for i in xrange(0,10):
try:
p.get_device_info_by_index(i)
except Exception,e:print e
So, I went over the Java's sound tutorial and I did not find it all so helpful.
Anyways, what I understood from the tutorial for recording sound from a mic is this:
Although they do show how to get a target data line and so on, they do not tell how you can actually record sound [or maybe I didn't get it all well].
My understanding so far has been this:
Mixer can be your sound card or sound software drivers that can be used to process the sound, whether input or output
TargetDataLine is used when you want to output your sound into the computer. Like save it to the disk
Port is where your external devices like mic, etc are connected
Problems that remain
How do I select the proper mixer? Java's tut says that you get all the available mixers and query each one to see if it has what you want. That's quite vague for a beginner
How do I get the port on which my integrated mic is? Specifically, how do I get input from it into the mixer?
How do I output this to the disk?
Using the AudioSystem.getTargetDataLine(AudioFormat format) method you will get
... a target data line that can be used for recording audio data in the format specified by the AudioFormat object. The returned line will be provided by the default system mixer, or, if not possible, by any other mixer installed in the system that supports a matching TargetDataLine object.
See the accepted answer for Java Sound API - capturing microphone for an example of this.
If you want more control of which data line to use you can enumerate all the mixers and the data lines they support and pick the one you want. Here is some more information regarding how you would go about doing that: Java - recording from mixer
Once you've obtained the TargetDataLine you should open() it, and then call read() repeatedly to obtain data from that data line. The byte[] that you fill up with data with each call to read() can be written to disk e.g. through a FileOutputStream.