Java-Gaming.org Hi !
Featured games (90)
games approved by the League of Dukes
Games in Showcase (739)
Games in Android Showcase (224)
games submitted by our members
Games in WIP (820)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  RainThunder  (Read 8708 times)
0 Members and 1 Guest are viewing this topic.
Offline philfrei
« Posted 2016-11-26 03:02:12 »



A procedural rain and thunder app: RainThunder.jar

Sample of audio output: RainThunderDemo.ogg

I wasn't sure whether to put this in a new thread or add it to the "forest ambience" thread from a short while ago. I think this is ready to show, despite there being room for improvement. It is a mild thunderstorm, not supercharged, Hollywood-level drama.

The source sf/x files came from http://freesound.org/people/lennyboy/sounds/244053/, if you are curious as to the original sound cue. I use about half of this cue (7 seconds).

The main new component is a "ClipSectionPlayer" tool. With it, you can specify sections of clips (my equivalent of the Java Clip, not javax.audio.sampled.Clip itself), and play them as a chain. Start and end frames are required. At this point a single cross-fade length is used for all the seams.

I vary the playback frequency to get different "intensities" (ranging from something like 1/2 speed to 3x's speed). At the faster playbacks, code adds more and longer sections to achieve similar lengths throughout the intensity range. It wouldn't be too hard to make the event length an independent parameter.

One challenge was making the taper long enough not to sound abrupt with the faster playbacks, without bringing in a long sample. After trying several approaches, I tried a crude granular approach: the first half of the decay sample is broken into many short overlapping fragments which are chained. Most of the thunder events, thus are made from just a few longer sections for the body, followed by numerous but shorter sections from the "tapering" sample.

The rain and wind use a clip-slicer tool (explained in earlier posts). I made a crude low frequency (LF) "noise" tool, to vary the volume of the rain and wind. At this point, the tool varies the "wind" slightly before the "rain", and errs on the side of subtlety. It seems to me, the LF noise wave should be filtered slightly (maybe with simple box filter) before using with the rain, on the theory that the rain reflects the sum of wind gusts occurring during its fall. Having a variable high-Q filter for the wind would be very helpful for more theatrical wind effects. As it stands, the wind is almost more a texture-thickener for the rain than something that reads clearly in its own right.

music and music apps: http://adonax.com
Offline J0
« Reply #1 - Posted 2016-11-27 18:40:21 »

You should bundle every one of your effects into one big jar Smiley
One question: what does the purple bar represent? I saw it moving but couldn't understand it...
Oh, also: do you think we might be able to use your ambiance library/libraries in our games? I'd love to be able to implement that kind of sound effects in my next project!

Offline philfrei
« Reply #2 - Posted 2016-11-29 19:14:47 »

You should bundle every one of your effects into one big jar Smiley
One question: what does the purple bar represent? I saw it moving but couldn't understand it...
Oh, also: do you think we might be able to use your ambiance library/libraries in our games? I'd love to be able to implement that kind of sound effects in my next project!

Thanks!

I'm curious what the purple bar is that you are seeing. The code only should have a simple JavaFX GUI with buttons and sliders. Are you referring to the 3D-Sound program where I was trying out a time-delay based algorithm for implementing 3D audio? In that, the purple cylinders that rise and sink in place, corresponding to audio source locations. They are loudest when tallest, and quiet when they sink into the "chessboard" floor.

I'm quite perplexed in terms of figuring out what to make freely available or not. I don't want to commit too much of the code yet, as part of my way of development includes rewriting fundamental parts of it as I learn more, and I don't want to be encumbered by obligations for backwards compatibility. (Ran into this with SiVi a couple years ago.)

Yes, it is possible to combine the various into a single library jar.

J0, when you are ready to seriously consider going forward, maybe you can message me and check in on the status of things. (Same to anyone else.) I'd like to be part of a team, and the audio expertise is one of the main things I can bring. I'm also looking for situations to implement "real-world" examples of the library being used.

music and music apps: http://adonax.com
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline J0
« Reply #3 - Posted 2016-11-29 20:55:15 »

By purple bar I meant this here

I now see it could very well be a separator... I've never used JavaFX honestly, so idk. On my computer the rightmost, say 4-5 pixels in width, move in a strange manner. Nevermind, my pc's haunted.

If my current project gets anywhere near something that might see the light of day sometime, I'll get back to you then Cheesy

Offline philfrei
« Reply #4 - Posted 2016-11-30 06:26:09 »

Yes, just a separator. I put very little into the GUI. It is just a series of JavaFX HBoxes, stacked one on top of another in a GridPane. The "separator" is an empty HBox with a background color:

1  
2  
3  
    HBox sectionBar = new HBox();
    sectionBar.setMinHeight(3);
    sectionBar.setStyle("-fx-background-color: #8080FF;");


Supposed to be light blue. Is kind of purple now that you mention it. It shouldn't have moved! Computer needs an exorcist?

I look forward to seeing what you come up with.

music and music apps: http://adonax.com
Offline Aalhex
« Reply #5 - Posted 2017-01-31 19:33:24 »

Let’s bring this thread back to life shall we!

First of all—great work on this!

Like J0, I’d love to use something like this for one of my games. Would there be any possibility of you bundling up just the important classes into a jar? I’ll make sure to put you in my game’s credits!

It is I, Alexander from the Junivörs.
Offline philfrei
« Reply #6 - Posted 2017-01-31 22:43:13 »

Quote
Would there be any possibility of you bundling up just the important classes into a jar? I’ll make sure to put you in my game’s credits!

Sure. A mention would be great! We can also go back and let the recordists at FreeSound.org know as well. There is no fee--these are free--but the recordists like to hear when something has been used in an app. I've got links to the original files.

Actually, you can try running the jar as is, if you link it into your project. The main "excess" is the GUI class which is pretty lightweight and can just be ignored, probably.

I was noticing the other night that if I have two or three sound-playing jars open at the same time, this one starts experiencing dropouts. It runs fine, otherwise, and has low cpu usage afaik. But for sure, test it before making it a go for your game. I have been planning to investigate as to what the bottleneck might be but haven't had a chance to follow through, yet. If it is happening in your game, please let me know and maybe we can look into it further.

Also--I can probably hone it down if you want to lose either the wind or rain parts or really do need to get rid of the GUI. The animation timer isn't needed for the thunder, just the wind/rain.

Below is the "SoundHandler.java" class that is used to control the app. Are you able figure out how to use the jar via the public methods here? I apologize for some laziness in the coding that might cause confusion, e.g., should have renamed updateVolume() to updateParameter() since it was expanded to do more than just set volumes.

So, make an instance of SoundHandler, and call soundHandler.start() to get the audio engine rolling. Then use the other start/stops to turn things on/off, and updateVolume, using the enum of parameters, for the aspect you wish to control. The parameters updates are set to respond to normals (0..1) for the ranges.

Be sure and include the stop() method when shutting down, or else the thread pool executor in EventSchedulingThreadPool will keep running.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
160  
161  
162  
163  
164  
165  
166  
167  
168  
169  
170  
171  
172  
173  
174  
175  
176  
177  
178  
179  
180  
181  
182  
183  
184  
185  
186  
187  
188  
189  
package com.adonax.weather;

import java.io.IOException;
import java.io.InputStream;

import javax.sound.sampled.UnsupportedAudioFileException;

import com.adonax.pfaudio.cliptools.SuperSlicer;
import com.adonax.pfaudio.core.CoreMixer;
import com.adonax.pfaudio.core.JavaWrapper;
import com.adonax.pfaudio.events.EventSchedulingThreadPool;
import com.adonax.pfaudio.io.PFClipData;

import converter.OggVorbisToPCMFloats;
import javafx.animation.AnimationTimer;

public class SoundHandler {
   private CoreMixer mixer;
   private JavaWrapper jw;
     
   private SuperSlicer windSlicer, rainSlicer;
   private float baseWindVol, baseRainVol;
   private float turbulence;
   
   private ThunderAmbience thunder;
   
   public enum Attribute { WIND_VOLUME, RAIN_VOLUME, TURBULENCE, THUNDER_VOLUME, THUNDER_INTENSITY,
      THUNDER_FIXED_PAUSE, THUNDER_RANDOM_PAUSE};
   
   public SoundHandler() throws UnsupportedAudioFileException, IOException
   {
      mixer = new CoreMixer();
      jw = new JavaWrapper(mixer);  
      new EventSchedulingThreadPool(10);
     
      float[] pcmFloats;
      PFClipData clipData;
      InputStream inputStream = null;

      // * * * * * * * *
      //   Forest Wind in Trees
      // * * * * * * * *
      inputStream = this.getClass().getResourceAsStream(
            "../wind/audio/25945__inchadney__owl__WIND_IN_TREES.ogg");
     
      if (inputStream == null) System.out.println("inputStream not found");
     
     
      pcmFloats = OggVorbisToPCMFloats.makePCMFloats(inputStream, 141_324);
      clipData = new PFClipData("wind in trees ogg", pcmFloats);
      windSlicer = new SuperSlicer(clipData, 44100 / 2, 1024 * 8);
     
      mixer.addTrack(windSlicer);
     
      // rain
      inputStream = this.getClass().getResourceAsStream(
            "../wind/audio/244053__lennyboy__thunder_rainclip.ogg");
     
      if (inputStream == null) System.out.println("inputStream not found");
     
     
      pcmFloats = OggVorbisToPCMFloats.makePCMFloats(inputStream, 93_904);
      clipData = new PFClipData("rain ogg", pcmFloats);
      rainSlicer = new SuperSlicer(clipData, 44100 / 2, 1024 * 4);
     
      mixer.addTrack(rainSlicer);
     
      // thunder
      thunder = new ThunderAmbience();
      mixer.addTrack(thunder);
     
      LFPeriodicNoise wave = new LFPeriodicNoise(30);
     
      AnimationTimer timer = new AnimationTimer()
      {
         final int TUBE_LEN = 24; // 60 = 1 second delay
         float[] delayTube = new float[TUBE_LEN];
         int iWrite, iRead;
         
         void updateDelayTube()
         {
            iWrite++;
            iRead++;
            if (iWrite >= TUBE_LEN) iWrite = 0;
            if (iRead >= TUBE_LEN) iRead = 0;
         }
         
         @Override
         public void handle(long arg0)
         {
            wave.setPeriod((int)((1 - turbulence) * 60) + 30 );
   
            float flt = wave.tick() * (turbulence/3);
            delayTube[iWrite] = flt;
            rainSlicer.setVolume( baseRainVol * (1 + delayTube[iRead]) );
            windSlicer.setVolume( baseWindVol * (1 + flt/2) );
           
            updateDelayTube();
         }

      };
      timer.start();
   }
   
   // *************************
   //    INTERFACE METHODS
   // *************************
   
   public void start()
   {            
      jw.start(null);
   }  
   
   public void stop()
   {
      jw.stop();
      EventSchedulingThreadPool.shutdown();
   }
   
   // Inputs should be normalized [0, 1]
   public void updateVolume(Attribute attribute, float value)
   {
      switch(attribute)
      {
      case WIND_VOLUME:
         baseWindVol = value / 8;
         
         break;

      case RAIN_VOLUME:
         baseRainVol = value / 6;
         
         break;

      case TURBULENCE:
         turbulence = value;
         break;
         
      case THUNDER_INTENSITY:
         thunder.setIntensity(value);
         break;
     
      case THUNDER_VOLUME:
         thunder.setMasterVolume(value);
         break;

      case THUNDER_FIXED_PAUSE:
         thunder.setFixedPausePart(value);
         break;
      case THUNDER_RANDOM_PAUSE:
         thunder.setRandomPausePart(value);
         break;

      default:
         break;
         
      }
   }  
   
   public void startWind()
   {
      windSlicer.play(0, 0);
   }
   
   public void stopWind()
   {
      windSlicer.stop();
   }
   
   public void startRain()
   {
      rainSlicer.play(0, 0);
   }
   
   public void stopRain()
   {
      rainSlicer.stop();
   }
   
   public void startThunder()
   {
      thunder.start();
   }
   
   public void stopThunder()
   {
      thunder.stop();
   }
}

music and music apps: http://adonax.com
Offline Aalhex
« Reply #7 - Posted 2017-02-01 09:02:12 »

I’ll make sure to give it a try in just a few days—I’ll get back to you should I experience some difficulties. Pointing

It is I, Alexander from the Junivörs.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 
Ecumene (48 views)
2017-09-30 02:57:34

theagentd (72 views)
2017-09-26 18:23:31

cybrmynd (182 views)
2017-08-02 12:28:51

cybrmynd (180 views)
2017-08-02 12:19:43

cybrmynd (187 views)
2017-08-02 12:18:09

Sralse (194 views)
2017-07-25 17:13:48

Archive (744 views)
2017-04-27 17:45:51

buddyBro (877 views)
2017-04-05 03:38:00

CopyableCougar4 (1423 views)
2017-03-24 15:39:42

theagentd (1316 views)
2017-03-24 15:32:08
List of Learning Resources
by elect
2017-03-13 14:05:44

List of Learning Resources
by elect
2017-03-13 14:04:45

SF/X Libraries
by philfrei
2017-03-02 08:45:19

SF/X Libraries
by philfrei
2017-03-02 08:44:05

SF/X Libraries
by SkyAphid
2017-03-02 06:38:56

SF/X Libraries
by SkyAphid
2017-03-02 06:38:32

SF/X Libraries
by SkyAphid
2017-03-02 06:38:05

SF/X Libraries
by SkyAphid
2017-03-02 06:37:51
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!