I've been working on this project with a peer for comp sci class, and I can't figure out how to make SFX and music have their own independent volume controls. Both the music and the SFX both play just fine when they need to (hovering/clicking on buttons, menu music, etc), and I made sliders for both of them (music volume and SFX volume), but for some reason only music can be controlled. I have sat here for hours trying to figure out why it doesn't work. The FloatControl gain does update with the slider (I printed out it's value and it was working just fine, just not updating the actual volume of the sound effects). I also got rid of everything to do with the music by commenting out everything regarding it's slider controls, audio input stream, gain control, etc; it was as if SFX was the only audio related thing in the program, but it still didn't work. I don't understand why since the code is identical to the music's code (just that "music" is now "sound").
The below code is not meant to be functional on it's own since the actual code is 605 lines so far and that's too long to post on here. It does contain the core components, so if you want to set it up to work you have to make the JFrame and all the buttons, or have me post the full code and sound files.
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.sound.sampled.*;
import java.awt.event.*;
import javax.swing.border.Border;
import javax.swing.BorderFactory;
import java.io.*;
import java.io.File.*;
import java.io.IOException;
public class AudioTesting {
// Declare Global Objects
static final String[] SFXName = {"menuHover", "buttonEnter", "buttonLeave", "gameStart"};
static final String[] TrackName = {"Bossfight_Incomplete"};
static final String userName = System.getProperty("user.name");
static Clip sound;
static Clip music;
static JSlider musicVolumeSlider;
static JSlider soundVolumeSlider;
public static void main(String []args){
GameSetting();
}
public static void GameSetting(){
musicVolumeSlider = new JSlider(-45,6,6);
soundVolumeSlider = new JSlider(-45,6,6);
musicVolumeSlider.setMajorTickSpacing(5);
musicVolumeSlider.setMinorTickSpacing(1);
musicVolumeSlider.setPaintTicks(true);
//musicVolumeSlider.setPreferredSize(new Dimension(SLIDER_SIZE_X,SLIDER_SIZE_Y));
// musicVolumeSlider.setBackground(menuColor);
musicVolumeSlider.addChangeListener(new SliderListener());
soundVolumeSlider.setMajorTickSpacing(5);
soundVolumeSlider.setMinorTickSpacing(1);
soundVolumeSlider.setPaintTicks(true);
// soundVolumeSlider.setPreferredSize(new Dimension(SLIDER_SIZE_X,SLIDER_SIZE_Y));
// soundVolumeSlider.setBackground(menuColor);
soundVolumeSlider.addChangeListener(new SliderListener());
}
//manages the loading and playing of sfx
public static void SFXManager(int sfx){
try{
sound = AudioSystem.getClip();
File sfxFile = new File("C:\\Users\\" + userName + "\\Documents\\" + SFXName[sfx] + ".wav");
sound.open(AudioSystem.getAudioInputStream(sfxFile));
}catch (Exception ex){}
sound.flush();
sound.start();
}
// manages the loading and playing of music tracks
public static void MusicManager(int track){
try{
music = AudioSystem.getClip();
File musicFile = new File("C:\\Users\\" + userName + "\\Documents\\" + TrackName[track] + ".wav");
music.open(AudioSystem.getAudioInputStream(musicFile));
}catch (Exception ex){}
music.start();
music.loop(Clip.LOOP_CONTINUOUSLY);
}
static class SliderListener implements ChangeListener {
public void stateChanged(ChangeEvent e) throws IllegalArgumentException {
float currentMusicVolume = 0;
float currentSoundVolume = 0;
FloatControl musicGainControl = (FloatControl) music.getControl(FloatControl.Type.MASTER_GAIN);
FloatControl soundGainControl = (FloatControl) sound.getControl(FloatControl.Type.MASTER_GAIN);
//-------------------------------------------------------------PROBLEM AREA v v v
//For changing the volume of the music (this works just fine)
if (e.getSource() == musicVolumeSlider){
currentMusicVolume = musicVolumeSlider.getValue();
//if the slider is all the way at it's lowest, set the volume to -80 (i.e. mute)
if (currentMusicVolume == -45){
currentMusicVolume = -80;
}
musicGainControl.setValue(currentMusicVolume); // Reduce volume by slider value
}
//for changing the volume of the sfx
if (e.getSource() == soundVolumeSlider){
currentSoundVolume = soundVolumeSlider.getValue();
//if the slider is all the way at it's lowest, set the volume to -80 (i.e. mute)
if (currentSoundVolume == -45){
currentSoundVolume = -80;
}
soundGainControl.setValue(currentSoundVolume); // Reduce volume by slider value
}
}
}
//-------------------------------------------------------------PROBLEM AREA ^ ^ ^
// I didn't implement it in here, but here is where all the mouse and event listeners go for the different buttons
// If a button is hovered over or pressed, it plays a sound from the index that corresponds with that sound
// I.e. if you hover over a button, call SFXManager(0); which plays the first sound in the array (buttonHover.wav) etc.
}
I've found these float controls to be kind of hit-or-miss, in part because they depend on the local PC and its OS. It's often the case that only the master gain works, if you want to change volumes in real time. The master gain changes will affect ALL the playing sounds.
You could follow the suggestion from the last paragraphs of the Oracle sound tutorial on audio controls and write your own volume controls. To do so requires intercepting the audio input stream, compiling the bytes into PCM, multiplying the PCM by a volume factor, converting the PCM back to bytes, and finally, shipping the bytes out via a SourceDataLine.
This is basically the plan I followed when I wrote AudioCue. You are welcome to use that code base as an example for rolling your own, or to import and directly make use of the files within your project. I tried to follow the Clip API as closely as I could, while adding real time volume controls for each playing audio instance. One limitation is that it only works with wav files. But if you can work with that, feel free to use the library. I'm happy to answer any questions if you have any trouble setting it up.
I'm currently learning how to make the program available as a Maven resource. I'm not clear on how the Gradle instructions work--another contributor did that part. It is pretty easy to just copy the five files into your project and use them with just a little tinkering to the import/package lines.
Related
I am making a virtual piano project and I have some transcribed sample songs. I would like to know if I could get the current note that the player is on, so that it could be displayed visually on a piano.
Edit: I'm still learning Java, so sorry in advance if I need some more explanation than usual.
You can create a ParserListener to listen for any musical event that any parser is parsing. I have adjusted one of the examples to print out the note position in an octave. You can modify this to find out exactly which note is pressed:
public class ParserDemo {
public static void main(String[] args) throws InvalidMidiDataException, IOException {
MidiParser parser = new MidiParser(); // Remember, you can use any Parser!
MyParserListener listener = new MyParserListener();
parser.addParserListener(listener);
parser.parse(MidiSystem.getSequence(new File(PUT A MIDI FILE HERE)));
}
}
//Extend the ParserListenerAdapter and override the onNoteParsed event to find the current note
class MyParserListener extends ParserListenerAdapter {
#Override
public void onNoteParsed(Note note) {
//A "C" note is in the 0th position of an octave
System.out.println("Note pushed at position " + note.getPositionInOctave());
}
}
Source: http://www.jfugue.org/examples.html
When JFugue is playing music, it is using javax.sound.midi.Sequencer to playback a MIDI Sequence. That means you can listen to the MIDI events themselves using a Receiver on the same MidiDevice, and since MIDI is a system-wide resource on your computer, you can even do this outside of Java.
Hello stackoverflow community! I am learning to program and am working on a "duck hunt" style javafx game for mobile devices where 3 types of ducks move horizontally across the screen. Each time a certain type of duck is clicked, that type of duck gets a point next to its name.
What I would like to do is display a global leaderboard after the game so you can see which type of duck was clicked the most out of everyone who has played the game. What is everyones preferred way of implementing something like this? If you have any questions please feel free to ask me. Thanks, -H.J.
Edit (4/20/16 1:40PM PST): Because my original post was put on hold because it was deemed to vague, I wrote up a very basic example program to help explain what I am trying to do. On my menu scene I would like to retrieve the total number of clicks on the red and green rectangles for everyone who has played this game worldwide, which is currently globalScoreRed and globalScoreGreen and set to 0 because this is one of the parts I need help with.
On the playGame scene, when you hit the GG button, I would like scoreRed and scoreGreen to be submitted to the leaderboard which would adjust the values when viewed from the menu screen.
This is a very bad game and I can attest is not a game I would enjoy playing, but I am trying to learn the concepts of how to send the values and retrieve them. Once again thanks for viewing my post and helping out, you are very much appreciated.
package LeaderboardHelp;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class LeaderboardHelpMain extends Application {
Stage window;
Scene menu, playGame;
private Rectangle targetRed = new Rectangle(40, 40);
private Rectangle targetGreen = new Rectangle(40, 40);
private int scoreRed = 0;
private int scoreGreen = 0;
private Text redScoreText = new Text("Red: " + scoreRed);
private Text greenScoreText = new Text("Green: " + scoreGreen);
private int globalScoreRed = 0;
private int globalScoreGreen = 0;
private Text globalRedScoreText = new Text("Worldwide Red Clicks: " + globalScoreRed);
private Text globalGreenScoreText = new Text("Worldwide Green Clicks: " + globalScoreGreen);
private boolean playable = false;
public static void main(String[] args) { launch(args); }
#Override
public void start(Stage primaryStage) throws Exception {
window = primaryStage;
Button startButton = new Button("Start!");
startButton.setOnAction(e -> window.setScene(playGame));
//menu scene layout
VBox menuLayout = new VBox(20);
menuLayout.getChildren().addAll(globalGreenScoreText, globalRedScoreText, startButton);
menu = new Scene(menuLayout, 600, 600);
Button ggButton = new Button("GG");
ggButton.setOnAction(e -> window.setScene(menu));
targetRed.setFill(Color.RED);
targetRed.setOnMouseClicked(event -> {
scoreRed += 1;
redScoreText.setText("Red: " + scoreRed);
});
targetGreen.setFill(Color.GREEN);
targetGreen.setOnMouseClicked(event -> {
scoreGreen += 1;
greenScoreText.setText("Green: " + scoreGreen);
});
targetRed.setTranslateX(50);
targetRed.setTranslateY(50);
targetGreen.setTranslateX(100);
targetGreen.setTranslateY(50);
greenScoreText.setTranslateX(500);
greenScoreText.setTranslateY(50);
redScoreText.setTranslateX(500);
redScoreText.setTranslateY(70);
ggButton.setTranslateX(250);
ggButton.setTranslateY(250);
//game layout
Pane gameLayout = new Pane();
gameLayout.getChildren().addAll(targetRed, targetGreen, redScoreText, greenScoreText, ggButton);
playGame = new Scene(gameLayout, 600, 600);
window.setScene(menu);
window.setTitle("Leaderboard Helper");
window.show();
}
}
Edit (4/20/16 8:45PM PST) So after more reading I came across oracles EchoServer example which is getting me on a track (not sure if its right or wrong track). I was thinking about having the server save the submitted scores in a text file. When the menu scene is called by client it will connect to the server and request the scores. The server will read the text file and send scores to the application client. When the GG button is pressed, the score is sent to the server which reads the text file, adds the news score to old score and then overwrites the score text file. Is there a better way of doing this? I do want this to be scalable allowing lots of users to add their score at the same time.
A web service would be required. A simple one that takes maybe the type of duck and the number of times it was clicked.
POST /duck/{type}/{clicks}
The web-service would need to be secured using HTTPS or HMAC, or better yet both.
For HMAC the key would need to be hidden and obfuscated in your code. Security is always breakable, its about making the effort not worth it for such a small payout to any would-be hacker.
To do HMAC properly one should use a NONCE when creating the digest (aka signature). The NONCE should have a short expiration time. Many implementations use the timestamp as a NONCE, other implementations have the NONCE being provided by the web service. For simplicity I would go with the former. If the NONCE is older than 2 or 3 seconds, then reject the request.
I want to connect sharp network scanner using morena api and twain. Everything is ok if scanner is reachable but when scanner is not reachable, jni library opens a select scanner window. I think it is twain ds screen, I want to disable this screen. If scanner is not reachable, I want to throw error instead of open select device window. When I stop application, this screen also close so I think it depends on java thread. Question is, how can I stop this window's thread without stop whole program. I can run main method in another thread, and I can find this thread id, but when I stop this thread it is not close select device window.
import SK.gnome.morena.Morena;
import SK.gnome.morena.MorenaException;
import SK.gnome.morena.MorenaImage;
import SK.gnome.morena.MorenaSource;
import SK.gnome.twain.TwainManager;
import SK.gnome.twain.TwainSource;
import javax.swing.*;
public class HelloWorld
{ public static void main(String[] args) throws MorenaException
{
TwainSource[] list = null;
try {
list = TwainManager.listSources();
} catch (Exception var4) {
list = null;
}
MorenaSource source= list[1];
System.err.println("Selected source is "+source);
if (source!=null)
{ source.maskUnsupportedCapabilityException(false); // Lesson 3
source.maskBadValueException(false); // Lesson 3
source.setVisible(false); // Lesson 2
source.setColorMode(); // Lesson 2
source.setResolution(300); // Lesson 2
((TwainSource)source).setUnits(TwainSource.TWUN_CENTIMETERS);
source.setFrame(0, 0, 7.8, 10.5);
System.err.println("Image resolution is "+source.getResolution());
MorenaImage image=new MorenaImage(source);
System.err.println("Size of acquired image is "
+image.getWidth()+" x "
+image.getHeight()+" x "
+image.getPixelSize());
}
Morena.close();
}
}
Do you ever want the window itself to pop up? If not you can try TwainManager.getDefaultSource() instead of hardcoding list[1], or TwainManager.listSources() to either build your own selection or evaluate for 0 results and throw your own error.
To use TwainManager.getDefaultSource():
MorenaSource source = TwainManager.listSources();
See Morena's TWAIN JTP Support for more info.
This question has to do with a game console I'm working on, and right now I am trying to write a Java program to simulate the console's DSP. That way, I know exactly what to do when I port it to actual hardware. But I am having trouble finding the right sound library. What I need is basically this: I have my own sound format, and I feed it into the DSP. It then decodes the data, processes post decode effects (echo, amplify, etc.), and splits the results into two sound waves for stereo output. I have everything planned out except a way to get my sound waves to my computer's sound card. So basically a more advanced version of a sine wave generator. And a little code sample to get me started would help. If I need to clarify anything, than let me know.
EDIT: Okay, so just to be clear the sound wave data will be stored in chunks in a byte array. So I need a way of playing sounds from there. And I don't want to dump the audio to a file and then play the file, that would take too long.
Here is one way to generate a sound using java.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.sound.midi.Instrument;
import javax.sound.midi.MidiChannel;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Synthesizer;
import javax.swing.*;
public class SimpleSound extends JFrame{
Synthesizer syn;
MidiChannel[] midChannel;
Instrument[] instrument;
public SimpleSound() {
this.setLayout(new BorderLayout());
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
JButton button1 = new JButton("Try");
this.add(panel);
panel.add(button1);
this.pack();
try {
syn = MidiSystem.getSynthesizer();
syn.open();
midChannel = syn.getChannels();
instrument = syn.getDefaultSoundbank().getInstruments();
syn.loadInstrument(instrument[90]);
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
makeASound();
}
});
} catch (MidiUnavailableException ex) {
ex.printStackTrace();
}
}
void makeASound() {
this.midChannel[5].noteOn(55,550);
// this.midChannel[5].noteOn(70,700);
// this.midChannel[5].noteOn(30,400);
}
public static void main(String[] args) {
new SimpleSound().setVisible(true);
}
}
You can experiment on the values in the code this.midChannel[5].noteOn(55,550);
You can find more explanations here: http://patater.com/gbaguy/javamidi.htm and here: https://docs.oracle.com/javase/tutorial/sound/MIDI-synth.html
Update:
I found another source from here http://www.automatic-pilot.com/midifile.html. It is a simple program demonstrating the creation of MIDI sound and then save it to a file. I made a modification to the last part so that the sound will be written to a byte array instead.
// write to byte array
ByteArrayOutputStream baos = new ByteArrayOutputStream();
MidiSystem.write(s,1,baos);
byte[] bytes = baos.toByteArray();
But I just think that the byte array contents may not have the same format as you what you already have in mind. May I know what is the format of the sound data that is usable to you?
This page pretty much covers all of what I needed. http://www.developer.com/java/other/article.php/2226701/Java-Sound-Creating-Playing-and-Saving-Synthetic-Sounds.htm
I have a set of images i want to add one after another and create a movie. I will be using Quicktime for java for this(I'm on a mac).
I searched the web i have found lots of examples that show how to play movies using qtj, but i can't find any code snippets or tutorials showing how i can create a movie frame by frame using qtj?
I've done this through QTJ with the MovieMaker class from processing libraries (GPL). Processing is pure java, though it can hide it for beginners.
Small tutorial:
Download Processing, open it, go to Sketch -> Show Sketch Folder, create a folder called "data", and put all your images inside that folder, named "filename01.gif" through "filename09.gif". Paste the following code into the editor, and hit play:
/**
* Makes a QuickTime movie out of an array of images.
*/
import processing.video.*;
MovieMaker mm;
PImage[] imageFrames;
int index;
void setup() {
size(320, 240);
int numFrames = 9;
imageFrames = new PImage[numFrames];
for( int i = 0; i < imageFrames.length; i++ )
{
imageFrames[i] = loadImage( "filename" + nf(i+1,2) + ".gif" );
}
// Save uncompressed, at 15 frames per second
mm = new MovieMaker(this, width, height, "drawing.mov");
// Or, set specific compression and frame rate options
//mm = new MovieMaker(this, width, height, "drawing.mov", 30,
// MovieMaker.ANIMATION, MovieMaker.HIGH);
}
void draw() {
if( index < imageFrames.length )
{
// show the image
image( imageFrames[index], 0, 0 );
// Add window's pixels to movie
mm.addFrame();
index++;
}
else
{
mm.finish();
// Quit running the sketch once the file is written
exit();
}
}
This will create a file "drawing.mov" from your images in the sketch folder. If you go to file --> export application, and then open the sketch folder and navigate to the folder application.macosx/source or application.windows/source, there should be a .java file that has the actual code, which should look like this:
import processing.core.*;
import processing.xml.*;
import processing.video.*;
import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.text.*;
import java.util.*;
import java.util.zip.*;
import java.util.regex.*;
public class movie2 extends PApplet {
/**
* Makes a QuickTime movie out of an array of images.
*/
MovieMaker mm;
PImage[] imageFrames;
int index;
public void setup() {
size(320, 240);
int numFrames = 9;
imageFrames = new PImage[numFrames];
for( int i = 0; i < imageFrames.length; i++ )
{
imageFrames[i] = loadImage( "filename" + nf(i+1,2) + ".gif" );
}
// Save uncompressed, at 15 frames per second
mm = new MovieMaker(this, width, height, "drawing.mov");
// Or, set specific compression and frame rate options
//mm = new MovieMaker(this, width, height, "drawing.mov", 30,
// MovieMaker.ANIMATION, MovieMaker.HIGH);
}
public void draw() {
if( index < imageFrames.length )
{
// show the image
image( imageFrames[index], 0, 0 );
// Add window's pixels to movie
mm.addFrame();
index++;
}
else
{
mm.finish();
// Quit running the sketch once the file is written
//exit();
println( "done" );
}
}
static public void main(String args[]) {
PApplet.main(new String[] { "--bgcolor=#e0dfe3", "movie2" });
}
}
To use pure java, you'll need to use core.jar and video.jar from the processing application folder on your classpath, and then compile this java code. Here's a function reference and a javadoc for the processing library. Here are the javadocs for the MovieMaker class. If you want, you can see the source to the MovieMaker class.
HTH
There is an export related piece of sample code here:
http://developer.apple.com/samplecode/ImportExport/listing1.html
It shows how a single native QuickTime Movie can be opened for reading and then be passed on to a MovieExporter component to create a new QuickTime Movie from it.
For the code to import a file for as source for writing, see
void importMedia()
For the code to export the source to a QuickTime Movie, see
void run()
It should be possible to open an image file using the same approach, though, as long as the file format of the input file is supported by QuickTime (like f.e. BMP).
You should be able to write a sequence of image files using most of this code as well.
The only point which you will have to investigate is which method you'll have to call to append additional frames to an existing Movie. It might work using the same API, but most likely you'll need to use another call.
If you have to dig for another method you should be able to find it in the QT Java Reference Documentation located here:
http://developer.apple.com/Java/Reference/1.4/Java14API_QTJ/
It's a hack and most likely poor in performance, but it might actually work.
And... I never tried this (I am a QuickTime for Windows guy by trade) so: sorry, no warranty = ).
Edit: If you are looking for a way to write frames to a QT Movie using an existing input buffer instead of reading the data from file using the QT API, there should be APIs for
this as well. Just check out the reference documentation.
Edit 2: Actually it might be worthwhile to check out the C/C++ API Documentation here, as naming of components and calls seems to follow roughly the same naming conventions (i.e. this might help to dig for the calls of the Java API you need) and the C/C++ Docs seem to be more thorough in terms of providing Guides and How To's as a starting point. The C/C++ Docs can be found here:
http://developer.apple.com/referencelibrary/QuickTime/index.html
The most interesting sections should be
Import & Export
Compression & Decompression
Have Fun!