-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Audio and Sound Processing #226
Comments
Would it be possible to provide 7.1 surround for cab setups that use the 7.1 to drive exciters? |
It really depends where we're going with handling new mechanisms and how we integrate them into the editor and finally runtime. For me, for everything that concerns scripting, there are no "new VPE tables", they are all new. So we should choose the way most convenient to the author (i.e. linking sounds directly in the editor to game mechanics or other elements), and during runtime they should be handled in the most efficient way. I also haven't dived into the SSF stuff, which should be part of our planning. There is also DOTS audio, but I haven't looked into what it is exactly either, it might be mainly centered around audio processing. |
Lets write a bit about audio for visual pinball engine. I think the audio system can easily get split into two parts: One is the part the sounds that are synthesized or sampled on a real pinball machine. These might be triggered by scripts or events and might also origin in VPinMame. The other is mechanical noises that usually occur as side-effect of the mechanical nature of pinballs. While the first one appears to be rather straight forward but should support to select a dedicated audio-output-device, the second is the kind of audio I want to focus on. At this point I want to split also this second kind of audio into two natures: One is the kind of complex audio that basically always sounds the same, for example the ball rolling into the trough. The other is the audio that occurs when collisions happen in the physics engine. Again, I like to focus more on the second kind as the first kind also seems to be very straight forward. Thinking about audio caused by phsical collisions, I found that all audio can easily be modelled by an Impulse Response (IR). Impulse responses are widely known for modelling reverb which uses Infinite Impulse Responses (IIR). The IIR models something I'd call a white-click-response. I chose this name because it is what you would hear if you have a white noise (a white noise is like static noise that covers all frequencies evenly) in a room and shut it off, the room would sound like that from the moment of shutting the source off. So for reverb (and also speaker simulations) these impulse responses are used infinetly which means that you play the IR (the white-click-response) for every single input sample multiplied by that sample including its phase. As the IR already contains all the spectral and temporal properties of the mass-feather system including its capabilities to resonate on certain frequencies, you get the complete audible character of the underlying materials captured in an IR that lasts only a few hundred samples (or millions of samples in case you capture the IR of an cathedral). In case of a pinball we don't care about reverb (yet), instead we need to cover the dry (reverb-less) sounds of materials hitting each other. That means that every combination of two materials requires a distinct IR. At pinballs 99% of the time, the ball is always the same material and thus we need IRs for the ball impacting each material once. Unfortunately this still only gives a rough picture because the shape and the impact position on a certain shape changes the IR. A special case will be rolling noises. The noise that occurs for a rolling ball is caused by many micro-impacts on the playfield or a ramp. No physics engine would ever calculate these impacts as they are far too many. So the phsics engine should create rolling events. I could imagine, that in every physicsframe the rolling path since the last frame is serialized as an audio-event that contains path between two points. These points are the touching points of the ball in the last and the current frame. The rolling event furthermore will require a the ball id (in case balls might have a different material) and the component id to determine the material the ball is colliding with. In general, I suggest to organize IRs in a tree structure. The root should be the ball material, then the material of the collision object, then the object itself and last a certain position on this object (if multiple IRs shall be blended). When a collision happens, the tree can be used to find the most specific IR. |
What you are describing has been covered pretty well in various research papers. This one may be of use.. |
Coming a bit closer to the actual implementation of audio in unity, there are AudioSources that take all audio from audio-clip-files. Only these pre-existing files can be played back in at a spatial position with unitys spatialization engine. However, I figured that the procedural audio of a rolling ball should not travel with the ball anyways because if it would do that, the doppler effect would kick in and the result would sound simply wrong. In reality, the rolling noise is not emitted by the ball but by the playfield which is stationary. Rolling Ball Collisions Flippers
When releasing the flipper the following sounds would play:
With these sounds one could easily imagine that pressing the flipper button only a very short time would result in:
I think the moving sounds should stop every time another sound is played. Any other sound should continue playing to its end. The volume of the stop sounds (which are the noisiest ones) relates to the change of the rotation speed of the flipper. |
Sounds good! However we already have GameObjects for all elements on the playfield, so I don't think you'll need to spawn anything. |
Yea, I am not sure about this. Generally you are right, but there is one exception which makes me think over this and come to an unexpected result: |
Sound comes from every vibrating object, and more specifically, from every surface point of the vibrating object. You can then imagine that it is, in practice, impossible to simulate accurately, in particular in Realtime applications like VPE or any pinball simulation. You can of course set an audiosource to every object (because for example, rolling can occur not only on playfield, but also on ramps and every object...) but this would require some iniial computation to "transport" the sound to the emmiter position. Keep in mind that this is still approximation. This is why we usually sets the ball as the audio source: collision/rolling sound is almost always generated by ball or solenoids and it is convenient and efficient way to simulate spatial sound. In UP/UP2, there is an pool of impact sounds and rolling sound attached to each ball and one audio source to each solenoid object. But after a though, I would externalize the "impact sound" pool to a global one as, once an impact sound is produced, the spatial position where it originates from must not move with the ball (which is the case for rolling ones). This would answer the two colling balls problem: one sound for one impact, as an impact is always from 2 objects and it stays in the collision location until fully played, then pulled back in the pool when available.... |
Oh and in UP2, there is also audio sources from speakers positions which plays PinMame engine simulated sound.... |
Ok, I don't really know what UP is in this context. I thought VPE had no sounds yet. |
Typically in games we simplify by positioning the sound emitter at the location of the impact. This is a useful approximation because the information is provided with the impact event and no further calculations need to be done. The ball should probably be the emitter, not the playfield, as the ball is not guaranteed to be rolling on the playfield. This is how we handle footsteps in games with characters. The ground is not the sound source, the impact location is. A simple ray check with an origin at the ball location and a down vector is sufficient to find the contact point and object, from which the physical material ID can ge obtained. |
Playing the sound on both colliding objects make many things more simple:
Rolling sounds are covered on an entirely different way. There is no step-sound that can be played once a while. Spatial movement of procedural audio seems to be not possible at this point. |
UP (Unit3D Pinball) is a pinball simulation I made in Unity a while ago, and I used to develop the version 2. Unfortunately, I was blunt by development and did not saw VPE project until late so I made a lot of things... doubled. But (@freezy may agree with that, no offense), we went farther than VPE in the Player aspect at least (UP was able to play 15 tables fully in Unity, sound, physics, PinMame, etc...). So I already encountered all those problems a while ago (even on UP1, started in Unity 5!). I just give my humble opinion on how I resolved/should have resolved it. (BTW, I still have to open source UP and I think there will be a lot of things that actually can help with VPE. I already shared FP importer, but sadly, I really don't have much time to help you guys with VPE right now, just some little things here and there.) I am glad though to see new approaches for sounds in particular, but for everything else. Good luck |
Rolling sounds are indeed different from stepping sounds. Instead of a one off play, it is always playing when the velocity of the ball greater than zero. It is still modulated in discreet steps at a fixed frequency depending on which update function you utilize. Basic premise is simple: Futher extensions can be made in the case of multiple constant contact locations, i.e rolling while hugging a wall. Though those are only necessary when the material differs from the base and can be determined by detecting if a collision has been occurring for longer than a set threshold. If spatialization of pure code audio is not possible, it may be possible to supply a base audio noise as a static looping clip, then modulate the clip using a filter stack that is procedurally adjusted according to sampled parameters. I think that volume modulation based on geometry alone is likely to be insuffient. It may be beneficial to experiment with modulation of other parameters based on the impact velocity and physical properties. A larger object is not just louder, it has a different general tone. For simplicity sake, there need only be one ball type. The physical materials of the environment can be generalized as base materials, if which there are only a handful that need description: Wood Because we only have a metal ball type, which covers over 99% of use cases, the matrix is simple. More variation in the Audio landscape will arise as a result of property modulation based on the geometry, impact angle, impact location and impact velocity. While I've not implemented this system for pinball, I've implemented it for other games and the results were good while remaining efficient. Playing two audio sources is probably an unnecessary expense, though worth experimenting with just to see. |
@Pandelli Totally agree. These are almost the classes I used in UP/UP2 To be more specific, two sounds for each pair of the matrix: one for impact, one for rolling. Then, for each pair of collision, a queue is kept and check on next step to see if the contact is lasting. If it is,the rolling sound volume is updated (right now, only with relative velocity, which is almost always the velocity of the ball only as rolling sound almost never occurs between two moving objects like two balls). Rolling sound is discarded if the contact has stopped and then pushed back in a pool. (Please keep in mind I a m not saying this is what needs to be done, it's what I have right now in UP2) |
I've updated the main description. |
I think unity doesn't support multiple AudioSources on one gameObject or multiple clips on one AudioSource. To overcome this limitation, I could imagine instead of an AudioSource a list could be implemented as component that generates temporary GOs with audiosource every time it is played. Regarding the mode with starting, stopping and looping. I think authors can have another flag that defines if multiple play-calls may overlap or if the second call Stopps the first one. |
There is one more thing regarding sounds that could be a thing (maybe not for an MVP but after that): There would be other ways to approach that and I just would like to make this a topic. Another way would be one sample for a start-to-end rotation forward and another one for the same backward. Then if the rotation reverses in the middle, the forward sound can be stopped and the backward sound can be played starting somewhere in the middle. As @freezy already mentioned we are talking about "Sounds" and "Clips/Samples..." a sound is a more abstract concept that may play one of multiple clips. Maybe the sound could be some kind of interface that is somewhat an event listener.
All these are just ideas that one could keep in mind if starting with a RandomSound class :) |
Wrong! Unity CAN handle multiple AudioSources on One object (btw, if it where not, it would be easy to setup mock children for each audiosource). The limitation is regarding AudioListener: there can be only one in the scene I think, which makes sense to render spatial audio and it is most of time setup on the camera. As a matter of fact, Addams was the very first table I made for UP. We did not went so far as starting/ending sound for bookshelf, just motor one and to be honest, this was already immersive and enough with pingpong loop. |
Perfect. Nice to hear that I was wrong regarding this limitation. I must have understood something wrong... The motor of the bookshelf was maybe a silly example. I really see the main use for the sound of the flippers. Which in my oppion audibly sound wrong in vpx if you revers the flipper rotation midway. |
I'd like to suggest implementing a layer of abstraction for mechanical sounds similar to how music instrument sampling has evolved in the MIDI / digital audio workstation domain. I'm fairly new to VPin but have experience in the audio sampling world, where a MIDI drum kit seems fairly analogous to mechanical table sounds: with Kick Drum, Snare, Tom Tom, etc similar to Solenoid, Flipper, Bumper, etc. There are two ideas in drum kit sampling I see as potentially useful to this use case:
If it would be helpful I can provide representative UI screenshots etc from various instrumental sampling plug-ins which have evolved over the past couple decades to be quite intuitive yet powerful. |
Absolutely! I'm closing this, because the current discourse is happening in #449. There's also a PR with the first part implemented (#453). To your points:
Let me know if you'd be willing to work on this, I'll be soon back on this project again, once dmd-extensions's next version is final. |
In terms of audio, we can roughly distinguish between two different types of sounds:
In the following I'll dive into each of those categories and explain how VPE should handle it. This is of course subject to discussion, and I'll update it should there be better approaches.
Game Sounds
For ROM-based games, this is pretty trivial and already implemented: We get a sample buffer from the ROM and write it back to Unity's buffer in
OnAudioFilterRead().
We even patched PinMAME so it sends floats so we don't have to convert it anymore.For original games, we should probably distinguish between a few differnet types of sound such as music, sound effects and shout-outs. This is low-prio at the moment, and will be spcificied more in detail in another issue.
Game sounds are in stereo, although the vast majority of ROMs produces mono sounds, which then are sent to both channels.
Mechanical Sounds
We split mechanical sounds into two categories: Ball rolling sounds and all other sounds. What makes ball rolling sounds special is that they are not predefined but depend on the ball's velocity, position, and produce data as long as the ball rolls. We call the other sounds static sounds, since they are stationary and only depend on distinct data such as a hit event, rather than a time-dependent data sequence.
The source of mechanical sounds is in mono, and they get spatialized through Unity's audio mixer, based on the emitting object's position in space.
Static Mechanical Sounds
These sounds are recordings from a real pinball machine and are played when the respective event occurs.
However, since playing the same recordings over and over won't sound very realistically, we should allow authors to provide multiple recordings per sound. Additionally, an author should be able to randomly change the pitch and speed of the sound.
We call recording, sample or clip the single recording, and sound the lot with multiple recordings.
There is another factor, which is that not all balls are made out of steel. Some games like TAF have a ball made out of ceramic that is lighter. Thus, authors should be able to assign a sound (made of potentially multiple recordings) per ball material.
Triggering
There are two ways of triggering a sound: By a physics event such as a collision, or by GLE events such as a coil event. Authors should be able to configure sounds to be only triggered to start, or both to start and end. For the latter, they should be configured to either loop, or play only once.
Configuration
Since mechanical sounds are positioned in space, they should each configured on the game object that emits them. This should be done with a component that pulls the relevant physics events from the game item component.
Additionally, it might be worth thinking about a global sound manager so sounds can be quickly set up without having to navigate too much through the hierarchy. As @Pandelii noted, there are probably not so many different sounds, so authors should be able to easily reuse them.
Ball Rolling Sounds
This is still R&D and will be developed as we go.
The text was updated successfully, but these errors were encountered: