• Post Reply Bookmark Topic Watch Topic
  • New Topic

Is there a way to produce sound with Java?  RSS feed

 
Kevin Simonson
Ranch Hand
Posts: 208
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm in the beginning stages of writing an educational game in Java. I'd like to write the game with the capability of generating noises at different points in the game, maybe a short little melody as a response to a player getting something right, and a long bleep as a response to a player getting something wrong. Up to three players can play, so it would be nice if I could get the melody and bleep to occur at different tones, say the first player at one tone, the second player at a half an octave higher, and the third player half an octave still higher. Is there any way to do that in Java?
 
Campbell Ritchie
Sheriff
Posts: 54067
130
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Of course there is. Start by looking through the Java™ Tutorials.
 
Junilu Lacar
Sheriff
Posts: 10890
158
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have found the Princeton utlity library useful. http://introcs.cs.princeton.edu/java/stdlib/

I used the StdAudio and Tone classes to add sound to a Morse code program I wrote earlier this year.
 
Junilu Lacar
Sheriff
Posts: 10890
158
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
See also this page for frequencies of various musical notes http://www.intmath.com/trigonometric-graphs/music.php
 
Campbell Ritchie
Sheriff
Posts: 54067
130
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I like the explanation of equal temperament in that link. J S Bach knew about it and wrote the Tempered Keyboards (German das Wohltemperirte Clavier) to exploit it by using all twenty‑four keys.
 
Anurag Verma
Ranch Hand
Posts: 170
Hibernate Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Something to play with is here as well -
http://alvinalexander.com/java/java-audio-example-java-au-play-sound
 
Kevin Simonson
Ranch Hand
Posts: 208
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Campbell Ritchie wrote:Of course there is. Start by looking through the Java™ Tutorials.

I followed that link, and have been reading page after page about MIDI, channels, instruments, voices, lines, synthesizers, sequencers, etc., etc., and it's driving me crazy. I just want to know how to write some Java code that produces a little melody of just four notes, at three different pitches. Can anyone tell me where in the Java Tutorials it talks about code that produces just a short melody? I don't want to capture the melody and reproduce it; I just want to generate the melody so the user can hear it. Can anybody help me? Are there key words in the Java Tutorial for doing that that I can use to scan through the pages for the Java Tutorial and get the information I need?
 
Stephan van Hulst
Saloon Keeper
Posts: 7207
118
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
A melody is basically a Track containing a MidiEvent for each note that starts playing, and one for each note that stops playing.

When you've added all notes to a Track of a Sequence, you should hook up a Sequencer to an output device, and let it start the sequence.
 
Kevin Simonson
Ranch Hand
Posts: 208
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephan van Hulst wrote:A melody is basically a Track containing a MidiEvent for each note that starts playing, and one for each note that stops playing.

When you've added all notes to a Track of a Sequence, you should hook up a Sequencer to an output device, and let it start the sequence.

Okay, now as I understand it there are twelve notes in an octave, namely A, A#, B, C, C#, D, D#, E, F, F#, G, and G#. (Correct me if I'm wrong.) Let's say I want a melody consisting of five notes, each lasting .2 seconds, namely C, followed by D, followed by C, followed by B, followed by C. It sounds like what you're saying is that I need to create a {MidiEvent} for each of those five notes. The only constructor for {MidiEvent} takes two arguments, a {MidiMessage} and a {long}. What {MidiMessage} and {long} do I create a {MidiEvent} with to get a C note that lasts .2 seconds?
 
Stephan van Hulst
Saloon Keeper
Posts: 7207
118
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I would first create classes that represent keys, notes, times, fractions and melodies, before you convert them to MidiEvents. For instance, this is what a Note could look like:

And a Melody like this:

This should give you enough of an idea. I wrote this without a compiler, so it may contain errors, and you'll have to add some missing classes (Key and Fraction) and add exception declarations.
 
Stephan van Hulst
Saloon Keeper
Posts: 7207
118
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You could create your melody like this:
 
Kevin Simonson
Ranch Hand
Posts: 208
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephan van Hulst wrote:You could create your melody like this:

I translated that to:

What imports do I need to make to get this to compile? In other words, where are {Fraction}, {Note}, {Key}, and {Melody} located? I couldn't find them in "https://docs.oracle.com/javase/8/docs/api". Are they part of Java 9?
 
Carey Brown
Bartender
Posts: 2608
40
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Kevin Simonson wrote:What imports do I need to make to get this to compile? In other words, where are {Fraction}, {Note}, {Key}, and {Melody} located? I couldn't find them in "https://docs.oracle.com/javase/8/docs/api". Are they part of Java 9?

See Stephan's other post.
 
Kevin Simonson
Ranch Hand
Posts: 208
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephan van Hulst wrote:I would first create classes that represent keys, notes, times, fractions and melodies, before you convert them to MidiEvents. For instance, this is what a Note could look like:
..........snip..........

This should give you enough of an idea. I wrote this without a compiler, so it may contain errors, and you'll have to add some missing classes (Key and Fraction) and add exception declarations.

The only thing these files tell me about class {Fraction} is that it has an {atTicks()} method that takes as parameters an {int} and a {Fraction}. What exactly does {atTicks()} do? Is it a simple multiplication?
 
Kevin Simonson
Ranch Hand
Posts: 208
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Kevin Simonson wrote:
The only thing these files tell me about class {Fraction} is that it has an {atTicks()} method that takes as parameters an {int} and a {Fraction}. What exactly does {atTicks()} do? Is it a simple multiplication?

Typo. Meant to say {asTicks()}.
 
Stephan van Hulst
Saloon Keeper
Posts: 7207
118
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That would be asTicks(int ticksPerQuarterNote). I made a mistake, you don't need the timeSignature parameter. asTicks() converts the duration of a note specified in fractions of a bar, to duration of a note specified in ticks, where a tick is a length of time that depends on the resolution of the sequence.

Imagine that you want to play a note for the duration of a quaver. That's 1/8 of a bar. Let's say that the resolution of the sequence is 96 ticks per quarter note. That means 1/4 of a bar contains 96 ticks. A single quaver would then be 48 ticks. If you want to play a minim, which is 1/2 of a bar, it would have to last for 192 ticks.

Why perform this conversion? MidiEvent uses ticks to specify the time of the event.

What else does Fraction have? For now, it just needs a numerator() and a denominator().
 
Kevin Simonson
Ranch Hand
Posts: 208
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephan van Hulst wrote:That would be asTicks(int ticksPerQuarterNote). I made a mistake, you don't need the timeSignature parameter. asTicks() converts the duration of a note specified in fractions of a bar, to duration of a note specified in ticks, where a tick is a length of time that depends on the resolution of the sequence.

Imagine that you want to play a note for the duration of a quaver. That's 1/8 of a bar. Let's say that the resolution of the sequence is 96 ticks per quarter note. That means 1/4 of a bar contains 96 ticks. A single quaver would then be 48 ticks. If you want to play a minim, which is 1/2 of a bar, it would have to last for 192 ticks.

Why perform this conversion? MidiEvent uses ticks to specify the time of the event.

What else does Fraction have? For now, it just needs a numerator() and a denominator().

Then I've decided that my "Fraction.java" will look like this:

How does that look? And then for "Key.java" I've got:

Should that do the trick?
 
Kevin Simonson
Ranch Hand
Posts: 208
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Make that:

 
Stephan van Hulst
Saloon Keeper
Posts: 7207
118
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
  • Make your class final.
  • Make your fields private and final.
  • Normalize your fields in the constructor using BigInteger.gcd().
  • Your compareTo() method does not take overflow into account. You're better off using BigInteger instead of long.
  • If you make a class Comparable, you should override equals() and hashCode() as well.
  • Override the toString() method.
  • Key should start with C, otherwise the noteNumber() formula will not work. I would also write out the sharps:
  •  
    Tim Holloway
    Bartender
    Posts: 18552
    61
    Android Eclipse IDE Linux
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    OK, I'm late to the party and there's enough already written that I may have missed this part, but it looks like you're all giving advice on how to get Java to do MIDI sound. But this is a video game, so most likely that isn't what Kevin wants.

    MIDI is a digital control protocol. Originally, you'd have used it to play an external musical instrument like a synthesizer. These days, many OS's have internal MIDI client capabilities as well. But that would be overkill for the average videogame.

    The Java sound API also includes the ability to play digital sound samples. For a video game, you'd most commonly keep these samples in .wav files, although Java supports other formats as well.

    I don't have anything lying around handy right now, but basically you'd just load the file into RAM and tell the API to play it.

    You could also synthesize raw waveforms and play them, but it's easier to use pre-recorded samples.
     
    Carey Brown
    Bartender
    Posts: 2608
    40
    Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Tim Holloway wrote:OK, I'm late to the party and there's enough already written that I may have missed this part, but it looks like you're all giving advice on how to get Java to do MIDI sound. But this is a video game, so most likely that isn't what Kevin wants.

    MIDI is a digital control protocol. Originally, you'd have used it to play an external musical instrument like a synthesizer. These days, many OS's have internal MIDI client capabilities as well. But that would be overkill for the average videogame.

    The Java sound API also includes the ability to play digital sound samples. For a video game, you'd most commonly keep these samples in .wav files, although Java supports other formats as well.

    I don't have anything lying around handy right now, but basically you'd just load the file into RAM and tell the API to play it.

    You could also synthesize raw waveforms and play them, but it's easier to use pre-recorded samples.

    Agreed.
    If you are looking for royalty free sounds check out http://freesound.org/browse/
     
    Kevin Simonson
    Ranch Hand
    Posts: 208
    1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Stephan van Hulst wrote:
  • Make your class final.
  • Make your fields private and final.
  • Normalize your fields in the constructor using BigInteger.gcd().
  • Your compareTo() method does not take overflow into account. You're better off using BigInteger instead of long.
  • If you make a class Comparable, you should override equals() and hashCode() as well.
  • Override the toString() method.
  • Key should start with C, otherwise the noteNumber() formula will not work. I would also write out the sharps:

  • Okay, now I've got:

    and I've got:

    Does that look like it should work?
     
    Stephan van Hulst
    Saloon Keeper
    Posts: 7207
    118
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    It looks like you're doing a lot of juggling between long and BigInteger. Don't you think it's easier to just use BigInteger fields? Make them final while you're at it.

    Use the @Override annotation on equals(), hashCode(), toString() and compareTo(). You would have found that you're not overriding equals() correctly.

    You can implement equals() using compareTo(), and hashCode() using Objects.hash().

    Kevin Simonson wrote:Does that look like it should work?

    You should really write unit tests to test the correctness of your implementation.
     
    Kevin Simonson
    Ranch Hand
    Posts: 208
    1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Stephan van Hulst wrote:
    Kevin Simonson wrote:Does that look like it should work?

    You should really write unit tests to test the correctness of your implementation.

    Well, that's just the thing. For the code to be correct, it would need to actually sound a melody, and it doesn't. I modified "Stephan.java" like so:

    When I run "java Stephan", I get no sound at all. If I run "java Stephan r" I hear a couple of chimes, so I know the computer is capable of generating sound. But the {for} loop is generating no sound. What am I doing wrong? Am I leaving something out?
     
    Stephan van Hulst
    Saloon Keeper
    Posts: 7207
    118
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Yes, all this code does is convert notes to Midi events. The events still have to be sequenced and sent to a playback device.

    MidiSystem.getSequencer() returns the system's default sequencer, hooked up to a default playback device. Create a new Sequence, add your Melody to it as a Track, and use Sequencer.setSequence() and Sequencer.start() to sequence your Melody.
     
    Don't get me started about those stupid light bulbs.
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!