Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

A/V [RELEASED] Stem: Lightweight Audio Manager

Discussion in 'Tools In Progress' started by aviktorov, Jan 9, 2019.

  1. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28


    AVAILABLE ON UNITY ASSET STORE

    Stem
    is a robust and versatile audio manager that helps you with SFX, layered music, crossfades, music events without additional scene setup.

    Features

    • Supports layered music playback with independent playback controls
    • Supports sound variations: use multiple audio clips, randomize volume/pitch/delay for each clip
    • Supports 2d and 3d sound: tune the most important settings within the asset
    • Persistent playback: keep playing music and sounds while transitioning between scenes
    • Music events: handle playback and track changes in an easy way
    • Requires no scene setup: create a few assets and that's it
    • Optimized for runtime use: great performance, zero memory allocations per frame
    • Integrates with Unity 5 Audio: easily connect to a Unity mixer
    • Saves time with the batch import feature
    • All source code included

    DOCUMENTATION | API REFERENCE | ROADMAP

    Stem v1.1.1 is out!

    What's new


    1. Replaced 'edit' button to standard foldouts in bank inspectors;



    2. Improved API so it's possible to create sounds with variations and playlists from the code;
    3. Bugfixes and improvements (see changelog below)

    Stem v1.1 is out!

    What's new


    1. Support for old versions starting from Unity 5.5;
    2. Undo/Redo support for bank assets;
    3. ID system & custom attribute drawers (no directly typed string values in prefabs anymore);



    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class IDTester : MonoBehaviour
    4. {
    5.     [Stem.SoundID]
    6.     public int soundId = 0;
    7.  
    8.     [Stem.SoundBusID]
    9.     public int soundBusId = 0;
    10.  
    11.     [Stem.PlaylistID]
    12.     public int playlistId = 0;
    13.  
    14.     [Stem.MusicPlayerID]
    15.     public int musicPlayerId = 0;
    16.  
    17.     private void Start()
    18.     {
    19.         Stem.Sound sound = Stem.SoundManager.GetSound(soundId);
    20.         if (sound != null)
    21.             Debug.LogFormat("Found sound: {0}", sound.Name);
    22.  
    23.         Stem.SoundBus soundBus = Stem.SoundManager.GetSoundBus(soundBusId);
    24.         if (soundBus != null)
    25.             Debug.LogFormat("Found sound bus: {0}", soundBus.Name);
    26.  
    27.         Stem.Playlist playlist = Stem.MusicManager.GetPlaylist(playlistId);
    28.         if (playlist != null)
    29.             Debug.LogFormat("Found playlist: {0}", playlist.Name);
    30.  
    31.         Stem.MusicPlayer musicPlayer = Stem.MusicManager.GetMusicPlayer(musicPlayerId);
    32.         if (musicPlayer != null)
    33.             Debug.LogFormat("Found music player: {0}", musicPlayer.Name);
    34.     }
    35. }
    36.  
    4. Music callbacks (playback change, track change);

    Could be global:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class MusicManagerCallbacks : MonoBehaviour
    4. {
    5.     private void Start()
    6.     {
    7.         Stem.MusicManager.OnPlaybackStarted += OnPlaybackStarted;
    8.         Stem.MusicManager.OnPlaybackStopped += OnPlaybackStopped;
    9.         Stem.MusicManager.OnPlaybackPaused += OnPlaybackPaused;
    10.         Stem.MusicManager.OnTrackChanged += OnTrackChanged;
    11.     }
    12.  
    13.     private void OnDestroy()
    14.     {
    15.         Stem.MusicManager.OnPlaybackStarted -= OnPlaybackStarted;
    16.         Stem.MusicManager.OnPlaybackStopped -= OnPlaybackStopped;
    17.         Stem.MusicManager.OnPlaybackPaused -= OnPlaybackPaused;
    18.         Stem.MusicManager.OnTrackChanged -= OnTrackChanged;
    19.     }
    20.  
    21.     private void OnPlaybackStarted(Stem.MusicPlayer player)
    22.     {
    23.         Debug.LogFormat("[Global Callback] {0}: playback started", player.Name);
    24.     }
    25.  
    26.     private void OnPlaybackStopped(Stem.MusicPlayer player)
    27.     {
    28.         Debug.LogFormat("[Global Callback] {0}: playback stopped", player.Name);
    29.     }
    30.  
    31.     private void OnPlaybackPaused(Stem.MusicPlayer player)
    32.     {
    33.         Debug.LogFormat("[Global Callback] {0}: playback paused", player.Name);
    34.     }
    35.  
    36.     private void OnTrackChanged(Stem.MusicPlayer player, Stem.PlaylistTrack track)
    37.     {
    38.         Debug.LogFormat("[Global Callback] {0}: track changed to {1}", player.Name, (track != null) ? track.Name : "none");
    39.     }
    40. }
    41.  
    Or local:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class MusicPlayerCallbacks : MonoBehaviour
    4. {
    5.     [Stem.MusicPlayerID]
    6.     public int id = 0;
    7.  
    8.     private Stem.MusicPlayer cachedPlayer;
    9.  
    10.     private void Start()
    11.     {
    12.         cachedPlayer = Stem.MusicManager.GetMusicPlayer(id);
    13.         if (cachedPlayer != null)
    14.         {
    15.             cachedPlayer.OnPlaybackStarted += OnPlaybackStarted;
    16.             cachedPlayer.OnPlaybackStopped += OnPlaybackStopped;
    17.             cachedPlayer.OnPlaybackPaused += OnPlaybackPaused;
    18.             cachedPlayer.OnTrackChanged += OnTrackChanged;
    19.         }
    20.     }
    21.  
    22.     private void OnDestroy()
    23.     {
    24.         Stem.MusicManager.Stop(id);
    25.  
    26.         if (cachedPlayer != null)
    27.         {
    28.             cachedPlayer.OnPlaybackStarted -= OnPlaybackStarted;
    29.             cachedPlayer.OnPlaybackStopped -= OnPlaybackStopped;
    30.             cachedPlayer.OnPlaybackPaused -= OnPlaybackPaused;
    31.             cachedPlayer.OnTrackChanged -= OnTrackChanged;
    32.         }
    33.     }
    34.  
    35.     private void OnPlaybackStarted(Stem.MusicPlayer player)
    36.     {
    37.         Debug.LogFormat("[Local Callback] {0}: playback started", player.Name);
    38.     }
    39.  
    40.     private void OnPlaybackStopped(Stem.MusicPlayer player)
    41.     {
    42.         Debug.LogFormat("[Local Callback] {0}: playback stopped", player.Name);
    43.     }
    44.  
    45.     private void OnPlaybackPaused(Stem.MusicPlayer player)
    46.     {
    47.         Debug.LogFormat("[Local Callback] {0}: playback paused", player.Name);
    48.     }
    49.  
    50.     private void OnTrackChanged(Stem.MusicPlayer player, Stem.PlaylistTrack track)
    51.     {
    52.         Debug.LogFormat("[Local Callback] {0}: track changed to {1}", player.Name, (track != null) ? track.Name : "none");
    53.     }
    54. }
    55.  
    5. The ability to play the playlist from the startup (no coding required);

    music_player_play_on_start.gif

    6. Play button in sound bank inspector allowing to easily test & tune sounds;

    sound_play_in_editor.gif

    7. New music player sample & sample selector.

    music_players_sample.gif

    Change Log

    v1.0
    - Initial asset release

    v1.0.1
    - Persistent: fixed crash caused by wrong sound bus polyphony default value - Runtime: fixed music player shuffle

    v1.0.2
    - Persistent: added default bus property to SoundBus class
    - UI: fixed sounds not resetting the bus to default once the target bus was removed

    v1.0.3
    - Build: fixed crash due to attempt to save all assets including internal ones

    v1.0.4
    - UI: fixed inability to set a sound bus from the drop-down list in sound bank inspector

    v1.1
    - Feature: undo/redo support for bank assets
    - Feature: unique & persistent IDs for sounds, sound buses, music player and playlists
    - Feature: custom attribute drawers for sounds, sound buses, music players and playlists allowing easier selection (no directly typed string values in prefabs anymore)
    - Feature: music player callbacks (playback change, track change)
    - Feature: sound bank callbacks (sound add/remove/rename, sound bus add/remove/rename)
    - Feature: music bank callbacks (playlist add/remove/rename, music player add/remove/rename)
    - Feature: the ability to play the playlist from the startup
    - Feature: 'play' button in sound bank inspector allowing to easily test & tune sounds

    - API: added SoundInstance.Target property allowing to easily attach sound instances to game objects
    - API: added MusicManager / SoundManager method overrides that take IDs
    - API: added MusicManager.IsPlaying method
    - API: added index based MusicManager.Seek method
    - API: removed internal SoundBank.AddSound / AddSoundBus and MusicBank.AddPlaylist / AddMusicPlayer methods from API
    - API: removed MusicManager.UnPause method, improved music player play/stop logic
    - API: removed SoundInstance.Transform property, use SoundInstance.Target instead

    - Improvement: a drag-n-drop area for music banks allowing to quickly create playlists
    - Improvement: added two float fields under range slider for precise edits
    - Improvement: better sound & music bank inspector performance
    - Improvement: support for old Unity versions starting from 5.5
    - Improvement: added workaround for Unity popups so they'll show items with duplicate names
    - Samples: music player samples covering all basic features
    - Samples: added sample selector

    - Documentation: new articles in programming section covering bank management, id system and more

    - Fix: crash in MusicManager.Next / MusicManager.Prev due to zero tracks in playlist
    - Fix: crash caused by sound instance deletion if it was attached to a game object
    - Fix: crash for sounds with no variations
    - Fix: music player not stopping on track end with the auto advance flag set to false
    - Fix: music player not properly advancing playlist with the loop flag set to false
    - Fix: bank initialization & registration order

    v1.1.1

    - API: added Sound.AddVariation / Sound.AddVariations methods allowing to create sounds with variations from the code
    - API: added Playlist.AddTrack / Playlist.AddTracks methods allowing to create playlists full of tracks from the code

    - Improvement: added meaningful error messages to all SoundManager API methods
    - Improvement:

    - Fix: Stem won't create any game object during application quit
    - Fix: bank inspectors will take drag-drop events into account for undo/redo system
    - Fix: 'play' button now works if a sound was assigned to a newly created sound bus
    - Fix: fixed bank drawers not showing correct values in the play mode
     

    Attached Files:

    Last edited: Jun 5, 2019
    ij, zyzyx and BlackMat like this.
  2. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    Hi all, just a quick update here!

    Made online documentation with API reference and quickstart section, go check it out here: https://aviktorov.github.io/stem/

    The asset is almost ready. Video showcase will be soon.
     
  3. one_one

    one_one

    Joined:
    May 20, 2013
    Posts:
    621
    Looks pretty nice, but calling/referencing sounds by string seems kinda icky...
     
  4. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    Thanks for the feedback! I'm also working on the ID system so the user will choose what suits the best. I'll deliver it in version 1.1. By the way, what would you suggest to use instead of names?
     
    Last edited: Feb 5, 2019
    one_one likes this.
  5. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    one_one likes this.
  6. one_one

    one_one

    Joined:
    May 20, 2013
    Posts:
    621
    I'd suggest looking into the addressable assets system - it's still only in preview but seems like the best way to handle asset references in unity going forward. I do see that this would likely need to be optional for an asset, as a lot of people likely wouldn't be happy to be 'forced' to use addressables (in spite of how cool a system it is.)
    I'm not sure if you already handle sounds as nested ScriptableObjects, but that'd be a necessity for that. If you do set things up that way, you could also let users come up with their own in-code referencing system that they hook up to in-editor references to those nested SO instances.

    I have to admit that I don't quite see the use of sound banks quite yet (at least in the way they're used in your examples) - Sound Banks would make sense (for me) for sounds that are basically just variations of each other, where it makes sense to have the same pitch and volume variations. So, footsteps, impact sounds... In which case I'd just want to be playing a randomized sound from the bank, with randomized pitch etc.

    Another concept that I find very important for environment sound are 'soundscapes' - I believe there is an asset like that on the store already. In short though, they consist of various sounds (or in this case soundbanks?), paired with a probability for each sound/sound bank. I know that you're going for a lightweight approach, but I think that's a fairly common approach and IMO might be worth adding.

    I'm also quite interested in the music bank - will it also support per-layer sequential playback? That would be really sweet for dynamic soundtracks. EDIT: Just read in your first post that playback control is separate per layer. Sweet!
     
  7. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    I assume two things when I think about ids: they must be persistent (i.e. somehow stored on the disk) and unique (i.e. it should be possible to identify the instance and the bank). Your suggestion looks very good because it adds the ability to manipulate with bank parts as individual assets so it might be more native for the user. However, it'll restrict the asset to use latest Unity version.

    I see the whole sound bank concept as persistent storage for sound effects. Each sound effect is a collection of audio clips (variations) + audio and randomization settings.

    The main profit from having a 'sound bank' is a single place where you can find sound data. Stem will automatically load all available banks so you don't have to do anything other than creating a sound bank.

    If you like to organize stuff, you can split sound data into several sound banks. That way you're able not only to organize stuff but also add new content even during runtime (imagine a new asset bundle just came into the build and it contains new sound bank with new stuff). The cool thing is that you don't have to add or do something with that bank. It'll be automatically handled by Stem.

    Another use case is 'sound skins'. Imagine you have a sound bank full of player sound effects and then you have a level where you want to replace player sound effects. What you can do is create another sound bank with the same sound names and assign different clips to them. After that, all you need to do is to tell Stem which sound bank will be the primary bank. That way you'll be able to switch sound banks for different levels.

    Also, the cool thing is that when you work with SoundManager or MusicManager and access sounds by their names, the target bank the sound/music came from is hidden from you.

    Yeah, I like soundscape concept too! I'm thinking of creating a platform (like FMOD or WWise) where you'll be able to create an instruments and the whole sound scene. Think of if as DSP engine + Node Graph + 3rd party integration.

    You're absolutely right! Each music bank can contain multiple music players. Each music player has individual playback control and track advance logic (shuffle or sequential) so can do layered music.
     
    Last edited: Feb 6, 2019
  8. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    Last edited: Feb 6, 2019
    one_one likes this.
  9. one_one

    one_one

    Joined:
    May 20, 2013
    Posts:
    621
    These are definitely must-haves, I agree. By allowing users to also reference nested scriptable objects (not prefabs! nested scriptable objects have been possible for a long time) in the 'classical' unity way, you could let users create custom alternatives to string and/or addressables.

    That's the thing where I'm a little confused - on a functional part, sound banks appear to have a sound bus. So it also appears to be a functional grouping? Other than that, I'm not sure I see the benefit over sounds being regular files which can be sorted into folders - and with an individually assigned sound bus, which would also be an asset file? As you said further down, it's also a way of organizing things, and I personally think it's not so great to bundle organizing assets and assigning functional information like a sound bus. Or am I missing something here?

    Great! That's also essential for supporting user mods.


    Quite interested to see how that turns out! In the meantime, it sounds like it would be simple enough to build a simple system on top of this asset by adding information how often a certain sound should be played.

    Btw, sorry for seeming a bit negative or critical - this is actually because I think it's a good approach and I'm very interested :)
     
  10. RonnyDance

    RonnyDance

    Joined:
    Aug 17, 2015
    Posts:
    557
    Looks good.
    I am searching for a Soundsystem for my MMO. Thats why for me it's really important having mulitple random sounds in different locations like for example having 10 possible bird sounds in a forrest that can play randomly in different time intervals with random volume etc.

    Also for example having nice transitions of soundtracks / music when entering a fight. Same for different music when entering different zones like different cities or houses.

    Is this possible with your asset? How do you handle zones? Trough trigger colliders?
    Do you support networking for example with Mirror?

    Cheers
    Ronny
     
  11. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    I'll dig more into that, thanks!

    Yup, a sound bank could have a few sound buses which are used not only to group sounds but also to control how many of them could be played simultaneously. Think of it as a sound collection + mixer.

    The main reason why I decided to put everything in one place is ease of use because when you tune sound effects (especially if you delegate this job to another non-programmer person like composer or sound designer) it's very important to keep all stuff in one place just to have a better overview. The fewer mouse clicks you need to make a change the better. And yes, that lacks some cool features that are native to the asset system like duplication, referencing, ids, etc.

    I also thought it's easier to organize and manage a large sound library within a few sound banks, just because you don't have to remember every time where is the content. Please take note here that I'm looking from a sound designer perspective here (they tend to use DAWs with their sound libraries).

    You're right! Sounds like an interesting task to research. Might possibly ship it in the next version.

    That's why I created this thread in the first place — to get user feedback and suggestions so thank you so much!

    By the way, if I gave you a voucher for the asset would you use it and give me detailed feedback?
     
    Last edited: Feb 7, 2019
  12. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    There is no special component like "Soundspace" or "Environment sounds", however, it's really easy to build such a thing on top of Stem. All you need to do is to create a sound bank, organize sounds within the bank, create a "Soundscape" C# script and then use "Stem.SoundManager.Play" to play one-shot sounds. Stem will do the rest.

    Within the sound bank, you can group sounds to sound buses. In every sound bus, it's possible to set the maximum allowed simultaneously playing sounds. That way you can control your sound scene.

    In Stem it's possible to create music banks where you organize music into playlists. Each music bank can have multiple music players with individual volume & playbacks controls. For example, you can create multiple playlists (like "peaceful ost", "battle ost", "zone1 ambience", "zone2 ambience", etc.) and two music players (like "music" and "environment") as well as set the crossfade duration. Then it's up to you which playlist to set in both music players.

    Could you be more specific of what you're trying to achieve?
     
  13. one_one

    one_one

    Joined:
    May 20, 2013
    Posts:
    621
    Not sure if you're familiar with it already - but AddObjectToAsset is essentially what I was thinking/talking about - now that I think about it, I must admit I haven't tried out yet whether nested assets can be made addressable though...

    Ah, good point - you're of course right that it's a good idea to stick with conventions of other sound middlewares to make it easier to learn for sound designers.

    Definitely! I happen to be working on a small-ish project right now that would be a great testbed. I'd also try my hand at creating a small soundscape system on top of it. Plus I'm curious to see how nicely it can be integrated with some of the other architectural stuff I'm using, like dependency injection and a ScriptableObject database. So, yeah, I'm definitely interested!
     
  14. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    Sent the voucher, check your conversations. Please leave any feedback here even if it's not good. I'd very appreciate if you leave as many details as you can. Thanks again!
     
  15. ArkadiuszR

    ArkadiuszR

    Joined:
    Jan 21, 2016
    Posts:
    22
    Ok, so bug is:
    when I create my own sound bank and call:
    Stem.SoundManager.Play("Coin");
    I get error of null at
    (class = SoundBusRuntime, line 95) -> oldestSound.Sound = sound;
    BUT
    when i use your bank from sample and and there "Coin" - it work...
    Unity 2018.3.4f1.
    Sorry but i dont have time to fix it for you :/
    I do it few times with documentation, repo 100%.

    SS from hierarchy:
    upload_2019-2-15_0-11-33.png
     
  16. one_one

    one_one

    Joined:
    May 20, 2013
    Posts:
    621
    Ah. I'm having the same issue but I thought I broke it by my tinkering - so I didn't report it because I didn't manage to look into it yet further. On a quick glance it seems to be somehow tied to the sound banks - calling a sound from one of the sample sound banks works just fine, but fails with a custom sound bank. Seems quite weird that for custom sound banks the buses don't seem to get set up right?
     
  17. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    Thanks for report! Will send the fix ASAP.
     
    one_one likes this.
  18. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    Fixed. Please check your email for updated source code. The new version will be available soon on the asset store.
     
    one_one likes this.
  19. one_one

    one_one

    Joined:
    May 20, 2013
    Posts:
    621
    After tinkering with this for a bit my thoughts so far are:
    • The source code is clean and well commented. Definitely above common asset store code quality.
    • As can be seen in this thread, @aviktorov replies quickly and has patched the asset. I assume these to be initial woes but can't comment much yet on how stable/reliable it is because I haven't tested the asset in-depth for a longer time.
    • It's refreshingly simple to play a sound (once you have your sound bank(s) ready). It really reduces the amount of boilerplate setup and/or code around audio management.
    • Setting up sound banks is very quick and straightforward too and has a handy multi-audioclip import option
    • I haven't played around with the music manager yet, but based from my experience so far I'm looking forward to it.

    My personal suggestions/wishes:
    • The "edit" button for the foldout is a bit inconvenient as it breaks unity UI convention. I'm used to opening foldouts with the default arrow toggles in the inspector. Having to click that edit button still frequently requires conscious thought to do, which is slightly annoying.
    • Since sounds and buses are quite strictly tied to banks, I'd like to have more than one "primary bank". With the suggested use of "sound skins", I wouldn't necessarily want to swap out my entire bank of game sounds if I just want to change the sound set the UI is using.
    • An option to play/test single sounds & variations from the inspector to finetune pitch and volume variations

    As pointed out above, for a larger projects with stricter rules on software/project architecture it would be great to:
    • Reference sounds through something other than a string (ideally directly?), and by extension, be able to play a sound directly by reference. Maybe also the ability to specify buses outside of banks (and the ability to assign them to sounds.) I use a ScriptableObject based database and it would suit my workflow a lot better if I could just assign sounds there. It seems an ID system is already in the works, though!
    • I do get that the system with buses is designed with audio designers in mind, but as an allround dev it would feel more flexible, powerful and convenient if I didn't have to use banks on top of the core components of sounds and buses. It feels like it's a layer on top that could easily be stripped, but despite the code being well written and commented, the "automagical" setup and static API makes it a bit tricky to quickly create a workaround for that.
    • While I think that for smaller projects/teams who aren't as fixated on their architecture the setup is perfectly fine (and should stay the default), it would be nice to have an easy way to control the setup & lifetime of the stem manager, i. e. allowing devs to set it up ourselves via dependency injection, allowing devs more control over which sound banks are loaded etc. This is personal preference regarding architecture, though, and not a shortcoming of the asset per se.
    Even though it may seem like there's a lot of things I'd like changed, it's because I like the other stuff about this asset enough so far that I'd love to use it for larger projects with these requirements as well :)
     
    Last edited: Feb 25, 2019
    aviktorov likes this.
  20. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    Thanks a lot for suggestions! This would definitely affect Stem architecture in a good way.

    P.S. Thanks to William Chyr, I'm currently watching how the music system is implemented in Manifold Garden, the video has so many insights on requirements, problems and solutions!

     
    one_one likes this.
  21. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    Hi there! Status report.

    As I'm working on v1.1, I'd like to share the development process on Twitch. You're very welcome to watch and ask any question or provide feedback. The schedule is a subject of change but I tend to stream at least once a week on Wednesdays. I'll let you know once I figure this out.

    I've already made some cool changes for v1.1:
    - Added drag-n-drop area for music banks allowing to quickly create playlists
    - Added ability to play the playlist from the startup
    - Added unique & persistent IDs for sounds
    - Added custom attribute drawer for easier sound selection
    - Improved sound & music bank inspector performance
    - Improved support for old Unity versions starting from 5.5

    What's left:
    - Add unique & persistent IDs for sound buses, music players and playlists
    - Add custom attribute drawers for sound buses, music players and playlists
    - Add the ability to play sound in the sound bank UI for fast and easy iterations
    - Add more samples covering all basic features
    - Update documentation

    This version is still in development and not ready for production yet, however, I've released v1.0.4 with bugfixes and improvements so please go and check it out! You can find the full changelog in the first post.

    Thanks!
     
    Last edited: Apr 25, 2019
    one_one likes this.
  22. one_one

    one_one

    Joined:
    May 20, 2013
    Posts:
    621
    Cool! Even though personally I'd prefer (and I think that's probably the case for most others here) something like a public Trello board/roadmap to stay in the loop.
    Neat, I'm definitely enjoying the drag & drop for sounds! It's a nice idea that probably a couple of other assets should adapt as well.
    \o/
    Admittedly, the project I currently work on which uses Stem doesn't really have much content yet - but it's already giving me small bursts of existential dread every time I set up a reference to a sound via string :p
    Sweet.
    Yeah, admittedly the samples are all quite technical. Fortunately, the documentation is great so that kinda makes up for that. But this is the kind of asset that can, with some creativity, create some really neat things in projects - so I think it'd be great to also have samples with some more 'real-life'/game related samples for inspiration.

    Looking forward to the updates!
     
  23. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    That's actually a good idea, I'll think about making one. Thanks!

    What would you like to see as a sample? These are that comes to my mind:
    - How to create a soundscape for exploration kind of games
    - How to do music transitions between main menu and gameplay screens (could be also shown how to do it between separate scenes)
    - How to do a complex sound mixing (like a car engine)
     
    one_one likes this.
  24. one_one

    one_one

    Joined:
    May 20, 2013
    Posts:
    621
    Some more complex setups would definitely be welcome, my main point however is that examples tend to be easier to 'understand' if they're concrete examples of in-game usage. The setup with the microphone and moving speaker shows how a moving sound can be achieved using Stem and by itself is a decent sample. But to take the examples you mentioned, why not all of that in a mini-game, where you drive around a random vehicle in a simplistic world (maybe also with a simple collision sound system) with a couple of different soundscapes? Along with maybe a pause menu with music transitions.
    It would be a sort of 'case study' that shows how Stem can be used to take care of common audio use cases that could previously involve a lot of boilerplate code. IMO that's a lot easier to 'get' and transfer into projects than abstract moving sound source examples. I do realize that it might be a lot of work - it could however also be neat for advertising, to let players try that demo and then also supply a short overview of what it does and how it can be nicely set up with Stem, possibly even as a video. Just throwing some ideas out there, though, I get that these are all labour-intensive suggestions.

    I forgot to ask about the IDs - how will those be handled?
     
  25. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    Please take my apologies for the late reply (about a month of silence, geez). I've implemented own ID system to satisfy these requirements:
    1. An ID must be unique, i.e. once generated there must not be any other ID with the same value;
    2. An ID must be persistent, i.e. should have the same value between play sessions, in the editor, in the build and even when the editor is not running at all;
    3. The system must support old versions of Unity.

    Technically speaking, IDs are integer numbers stored within sound bank or music bank asset. The system also handles ID collision properly.
     
    Last edited: May 20, 2019
  26. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    Stem v1.1 is out!

    What's new

    1. Support for old versions starting from Unity 5.5;
    2. Undo/Redo support for bank assets;
    3. ID system & custom attribute drawers (no directly typed string values in prefabs anymore);



    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class IDTester : MonoBehaviour
    4. {
    5.     [Stem.SoundID]
    6.     public int soundId = 0;
    7.  
    8.     [Stem.SoundBusID]
    9.     public int soundBusId = 0;
    10.  
    11.     [Stem.PlaylistID]
    12.     public int playlistId = 0;
    13.  
    14.     [Stem.MusicPlayerID]
    15.     public int musicPlayerId = 0;
    16.  
    17.     private void Start()
    18.     {
    19.         Stem.Sound sound = Stem.SoundManager.GetSound(soundId);
    20.         if (sound != null)
    21.             Debug.LogFormat("Found sound: {0}", sound.Name);
    22.  
    23.         Stem.SoundBus soundBus = Stem.SoundManager.GetSoundBus(soundBusId);
    24.         if (soundBus != null)
    25.             Debug.LogFormat("Found sound bus: {0}", soundBus.Name);
    26.  
    27.         Stem.Playlist playlist = Stem.MusicManager.GetPlaylist(playlistId);
    28.         if (playlist != null)
    29.             Debug.LogFormat("Found playlist: {0}", playlist.Name);
    30.  
    31.         Stem.MusicPlayer musicPlayer = Stem.MusicManager.GetMusicPlayer(musicPlayerId);
    32.         if (musicPlayer != null)
    33.             Debug.LogFormat("Found music player: {0}", musicPlayer.Name);
    34.     }
    35. }
    36.  
    4. Music callbacks (playback change, track change);

    Could be global:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class MusicManagerCallbacks : MonoBehaviour
    4. {
    5.     private void Start()
    6.     {
    7.         Stem.MusicManager.OnPlaybackStarted += OnPlaybackStarted;
    8.         Stem.MusicManager.OnPlaybackStopped += OnPlaybackStopped;
    9.         Stem.MusicManager.OnPlaybackPaused += OnPlaybackPaused;
    10.         Stem.MusicManager.OnTrackChanged += OnTrackChanged;
    11.     }
    12.  
    13.     private void OnDestroy()
    14.     {
    15.         Stem.MusicManager.OnPlaybackStarted -= OnPlaybackStarted;
    16.         Stem.MusicManager.OnPlaybackStopped -= OnPlaybackStopped;
    17.         Stem.MusicManager.OnPlaybackPaused -= OnPlaybackPaused;
    18.         Stem.MusicManager.OnTrackChanged -= OnTrackChanged;
    19.     }
    20.  
    21.     private void OnPlaybackStarted(Stem.MusicPlayer player)
    22.     {
    23.         Debug.LogFormat("[Global Callback] {0}: playback started", player.Name);
    24.     }
    25.  
    26.     private void OnPlaybackStopped(Stem.MusicPlayer player)
    27.     {
    28.         Debug.LogFormat("[Global Callback] {0}: playback stopped", player.Name);
    29.     }
    30.  
    31.     private void OnPlaybackPaused(Stem.MusicPlayer player)
    32.     {
    33.         Debug.LogFormat("[Global Callback] {0}: playback paused", player.Name);
    34.     }
    35.  
    36.     private void OnTrackChanged(Stem.MusicPlayer player, Stem.PlaylistTrack track)
    37.     {
    38.         Debug.LogFormat("[Global Callback] {0}: track changed to {1}", player.Name, (track != null) ? track.Name : "none");
    39.     }
    40. }
    41.  
    Or local:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class MusicPlayerCallbacks : MonoBehaviour
    4. {
    5.     [Stem.MusicPlayerID]
    6.     public int id = 0;
    7.  
    8.     private Stem.MusicPlayer cachedPlayer;
    9.  
    10.     private void Start()
    11.     {
    12.         cachedPlayer = Stem.MusicManager.GetMusicPlayer(id);
    13.         if (cachedPlayer != null)
    14.         {
    15.             cachedPlayer.OnPlaybackStarted += OnPlaybackStarted;
    16.             cachedPlayer.OnPlaybackStopped += OnPlaybackStopped;
    17.             cachedPlayer.OnPlaybackPaused += OnPlaybackPaused;
    18.             cachedPlayer.OnTrackChanged += OnTrackChanged;
    19.         }
    20.     }
    21.  
    22.     private void OnDestroy()
    23.     {
    24.         Stem.MusicManager.Stop(id);
    25.  
    26.         if (cachedPlayer != null)
    27.         {
    28.             cachedPlayer.OnPlaybackStarted -= OnPlaybackStarted;
    29.             cachedPlayer.OnPlaybackStopped -= OnPlaybackStopped;
    30.             cachedPlayer.OnPlaybackPaused -= OnPlaybackPaused;
    31.             cachedPlayer.OnTrackChanged -= OnTrackChanged;
    32.         }
    33.     }
    34.  
    35.     private void OnPlaybackStarted(Stem.MusicPlayer player)
    36.     {
    37.         Debug.LogFormat("[Local Callback] {0}: playback started", player.Name);
    38.     }
    39.  
    40.     private void OnPlaybackStopped(Stem.MusicPlayer player)
    41.     {
    42.         Debug.LogFormat("[Local Callback] {0}: playback stopped", player.Name);
    43.     }
    44.  
    45.     private void OnPlaybackPaused(Stem.MusicPlayer player)
    46.     {
    47.         Debug.LogFormat("[Local Callback] {0}: playback paused", player.Name);
    48.     }
    49.  
    50.     private void OnTrackChanged(Stem.MusicPlayer player, Stem.PlaylistTrack track)
    51.     {
    52.         Debug.LogFormat("[Local Callback] {0}: track changed to {1}", player.Name, (track != null) ? track.Name : "none");
    53.     }
    54. }
    55.  
    5. The ability to play the playlist from the startup (no coding required);

    concepts_music_player_1.png

    6. Play button in sound bank inspector allowing to easily test & tune sounds;

    concepts_sound_1.png

    7. New music player sample & sample selector.

    music_players.png

    Plus a lot of fixes and improvements. You can see the full list in the first post.
     
    one_one likes this.
  27. one_one

    one_one

    Joined:
    May 20, 2013
    Posts:
    621
    No worries! So can the IDs be handled as references, e. g. drag and dropped?
     
  28. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    There are definitely could be handled as references, however, they cannot be dragged, because there's nothing to drag. In order to make it a lot easier, I made a bunch of custom attributes which you can use on int variables to set the correct reference to them.

    So this code:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class IDTester : MonoBehaviour
    4. {
    5.     [Stem.SoundID]
    6.     public int soundId = 0;
    7.  
    8.     [Stem.SoundBusID]
    9.     public int soundBusId = 0;
    10.  
    11.     [Stem.PlaylistID]
    12.     public int playlistId = 0;
    13.  
    14.     [Stem.MusicPlayerID]
    15.     public int musicPlayerId = 0;
    16.  
    17.     private void Start()
    18.     {
    19.         Stem.Sound sound = Stem.SoundManager.GetSound(soundId);
    20.         if (sound != null)
    21.             Debug.LogFormat("Found sound: {0}", sound.Name);
    22.  
    23.         Stem.SoundBus soundBus = Stem.SoundManager.GetSoundBus(soundBusId);
    24.         if (soundBus != null)
    25.             Debug.LogFormat("Found sound bus: {0}", soundBus.Name);
    26.  
    27.         Stem.Playlist playlist = Stem.MusicManager.GetPlaylist(playlistId);
    28.         if (playlist != null)
    29.             Debug.LogFormat("Found playlist: {0}", playlist.Name);
    30.  
    31.         Stem.MusicPlayer musicPlayer = Stem.MusicManager.GetMusicPlayer(musicPlayerId);
    32.         if (musicPlayer != null)
    33.             Debug.LogFormat("Found music player: {0}", musicPlayer.Name);
    34.     }
    35. }
    36.  
    Will look like this in the inspector window:
     
    one_one likes this.
  29. one_one

    one_one

    Joined:
    May 20, 2013
    Posts:
    621
    Ah, cool! :)

    Another thing I've wondered about is control over loading and streaming - particularly in two scenarios:
    1. Projects with a large amount of audio data - particularly music. Currently not there yet, but I could imagine it to be inconvenient to load everything directly in the beginning of the first scene.
    2. Adding sounds at a later point, e. g. when downloading asset bundles.
     
  30. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    1. Direct control over streaming via Stem is not there yet — this is a good idea what to do for v1.2. It's still possible to manually load or unload data from audio clips.
    2. Once you get the new bank, it's possible to register it via SoundManager.RegisterBank or MusicManager.RegisterBank. It's also possible to create a bank during runtime in memory without .asset file. I wrote an article about that in documentation: https://aviktorov.github.io/stem/manual/programming_bank_management.html
     
    one_one likes this.
  31. one_one

    one_one

    Joined:
    May 20, 2013
    Posts:
    621
    Alright, gave it a spin. I definitely like the new reference system so far! Picking the bank first and then the sound makes it actually really handy.
    Something I noticed though is that apparently I now need to add a SoundManager monobehaviour to a scene manually - is that correct? If so, it probably should be added to the quick start section of the documentation. Also, it might be nice to also throw in an assert in null checks rather than just quietly failing? (in this case in the FetchSoundManager() method)

    Looking forward to your next update, though. Hopefully with a sound preview feature (and removing that edit button in favour of a regular dropdown? :) )
     
  32. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    No, you don't have to manually add SoundManager monobehaviour, you just use the API as it was in previous versions. I'll add warning logs in case there's no sound / sound bus was found for particular name or id.

    Could you be more specific about the sound preview feature? Do you mean 'play' button to test & tune sounds right in the sound bank inspector? If so, then it's already there :)

    I'll do a UI polish pass in the next version, so hopefully, I'll be able to get rid of the 'edit' button as well.
     
  33. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    Alright, as asked, I made a public trello board where you can see current development status, submit a bug or suggest an idea. There's not too much content right now but it'll be filled with stuff after some time.

    Here's the link: https://trello.com/b/6KfNucz0/stem-roadmap
     
    one_one likes this.
  34. one_one

    one_one

    Joined:
    May 20, 2013
    Posts:
    621
    Woops, yeah, exactly! I missed that. Might be an interesting idea to color-code the buttons to make them more distinguishable? :) Perhaps even icons (I forgot whether that's semi-conveniently possible with the editor GUI) - when you're in the UI polish pass.

    Checked out the trello board to vote and add some ideas (and supply more detail about that issue I'm seeing.) I think that's a good way to communicate features & bugs, it's definitely worked well for other asset devs so far, too!
     
    Last edited: May 22, 2019
  35. kg-admin

    kg-admin

    Joined:
    Mar 27, 2019
    Posts:
    3
    hi,

    when i load soundbank from asset bundle(I built soundbank asset as a bundle), i got this exception:

    UnityException: get_isActiveAndEnabled is not allowed to be called during serialization, call it from OnEnable instead. Called from ScriptableObject 'SoundBank'.
    See "Script Serialization" page in the Unity Manual for further details.
    UnityEngine.EventSystems.UIBehaviour.IsActive () (at /Users/builduser/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/UIBehaviour.cs:28)
    UnityEngine.UI.Graphic.SetVerticesDirty () (at /Users/builduser/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Graphic.cs:223)
    UnityEngine.UI.Text.set_text (System.String value) (at /Users/builduser/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Text.cs:213)
    IngameDebugConsole.DebugLogManager.ReceivedLog (System.String logString, System.String stackTrace, UnityEngine.LogType logType) (at Assets/ThirdParty/IngameDebugConsole/Scripts/DebugLogManager.cs:387)
    UnityEngine.Application.CallLogCallback (System.String logString, System.String stackTrace, UnityEngine.LogType type, System.Boolean invokedOnMainThread) (at /Users/builduser/buildslave/unity/build/Runtime/Export/Application.cs:121)
    UnityEngine.Debug:LogWarningFormat(String, Object[])
    Stem.Sound:HandleIDCollision() (at Assets/ThirdParty/Stem/Scripts/Persistent/Sound.cs:386)
    Stem.SoundBankRuntime:AddSound(Sound) (at Assets/ThirdParty/Stem/Scripts/Runtime/SoundBankRuntime.cs:77)
    Stem.SoundBank:OnAfterDeserialize() (at Assets/ThirdParty/Stem/Scripts/Persistent/SoundBank.cs:180)
    UnityEngine.ResourceManagement.Util.DelayedActionManager:LateUpdate()


    how can i fix this? i use unity 2018.3
     
  36. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    Hi! Could you please provide a minimal reproduction sample so I'll be able to fix it quickly?
     
    Last edited: May 30, 2019
  37. kg-admin

    kg-admin

    Joined:
    Mar 27, 2019
    Posts:
    3
    Sorry, I found the problem, it is caused by our log system.
    when stem found a id collision, a log is output, but our log system got the log and produce the exception above.
    thanks for your quick reply.
     
  38. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    That's good to know! In case you'll have any troubles or issues in the future, feel free to describe it in public Trello board here: https://trello.com/b/6KfNucz0/stem-roadmap
     
  39. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    Stem v1.1.1 is out!

    What's new

    1. Replaced 'edit' button to standard foldouts in bank inspectors;

    foldout.gif

    2. Improved API so it's possible to create sounds with variations and playlists from the code;
    3. Bugfixes & minor improvements (see the full changelog in the first post).
     
  40. SuperSmithBros

    SuperSmithBros

    Joined:
    Jul 15, 2019
    Posts:
    4
    When playing a sound on an iOS device xCode is showing me the following error:
    SoundManager.Play(): can't find sound, ID: 1825747629

    The game doesn't crash but the sounds don't play, music plays fine just not SFX.

    In the editor all the sounds are working as expected. Any ideas why this might be?

    I can copy my implementation if need be but I basically just assign a soundID from the inspector and call SoundManager.Play(soundID);

    EDIT: Seems to happen in some builds but not in others. Im yet to discover why.
     
    Last edited: Aug 18, 2019
  41. duplexius

    duplexius

    Joined:
    Apr 24, 2015
    Posts:
    44
    Hello Andrey,

    I spotted a particularly nasty bug when using multiple sound id definitions like so:
    [Stem.SoundID] public int soundSelect;
    [Stem.SoundID] public int soundFail;

    When you add a new declaration to a Monobehavior, all previous values get set back to default.
    Unity 2017.4.29, Stem v1.1.1

    Console errors like this appear:


    PS: Could you please provide a support email in the Asset store? There must be a way to contact in case of errors. The Trello board issue submission doesn't work for me. It does not let me submit anything.
     
  42. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    Hi there! Thanks for the report, could you please send me a minimal reproduction sample or clear instruction so I'll be able to reproduce the issue. As for support email, you're totally right, I'll add a dedicated email address for it.
     
  43. Braza

    Braza

    Joined:
    Oct 11, 2013
    Posts:
    136
  44. Trombonesam357

    Trombonesam357

    Joined:
    Jun 11, 2018
    Posts:
    3
    upload_2020-5-16_19-30-25.png
    For some reason, while I'm working in the middle of my project, these warnings about the music player and playlist IDs getting regenerated pop up.
    This causes issues for wherever I'm using MusicPlayerID fields in the inspector. They get reset to none.
    I'll fill the fields back into the desired values, and before you know it, it gets reset again.
    Any ideas on how to fix the issue?

    To give some context, I'm using a separate music bank for each scene in my project, and I'm using Zenject to apply the music player id to every class and Monobehaviour that requires it in the SceneContext.
     
  45. Trombonesam357

    Trombonesam357

    Joined:
    Jun 11, 2018
    Posts:
    3
    So I somewhat found a workaround. I made prefab variants of the SceneContext GameObject for each Scene while plugging in different Music Player IDs for each prefab.

    This works as long as you don't close the project. If you close and reopen the project, the IDs will regenerate, and you'll have to go into each SceneContext prefab variant to plug in the Music Player IDs again.

    Suggestions?
     
  46. Trombonesam357

    Trombonesam357

    Joined:
    Jun 11, 2018
    Posts:
    3
    Ok, so I was able to reproduce the problem.
    I went to Sample Scene 5 in the project package and followed the following steps.
    1. Made a new Music Bank (with whatever names for the playlists and players).
    2. Referenced the music player and playlist ids in the Music Player Callback scripts attached to the @Logic Game Object.
    3. Opened a different scene, then returned to the Sample Scene 5.
    4. Looked at the Music Player Callback scripts attached to the @Logic Game Object in the inspector window to see that the music player id fields were set to none. I also noticed the following in the console.
    upload_2020-5-18_16-34-3.png

    I hope this helps. Please let me know if any more info is needed.
     
  47. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    Hi there!

    Wow, looks like I missed important alerts here, sorry about that and thanks for the bug report. I'm about to fix that issue and release the minor update to both Stem & Stem Pro. I hope to deliver that next week :)
     
  48. thegraphicsflow

    thegraphicsflow

    Joined:
    Jan 8, 2016
    Posts:
    3
    Hello,

    I purchased this asset a few days ago and so far I absolutely love the functionality, though there is a serious editor problem that is making me reconsider using Stem.

    I'm getting severe editor lag when looking at public ID variables inside the inspector, even when I'm only showing a couple. Unity chugs down to maybe 1 frame a second just having an inspector open with the ID variables shown. I've also tried this on a blank Unity project and still getting the same results. I'm defining ID's in the same way as shown in the documentation, I've also tried various other ways all still with the same result.

    Having a longer list like the one shown below makes use of the inspector almost impossible while the script is open and showing. Though I'm also getting this lag when defining any amount of public IDs, even 1 or 2. I'm using Unity 2018.14f1 and we need to keep it to this version.

    If there something I'm missing? I've followed everything the docs have explained exactly, though this seems like a very fundamental problem with the editor code that makes using the asset impossible.
     

    Attached Files:

  49. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    Hi! Thanks for reaching me and for the kind words, I really appreciate that.

    Could you please tell me your HW specs & create a minimal reproduction sample so I can see the problem on my side?
     
  50. aviktorov

    aviktorov

    Joined:
    Dec 5, 2012
    Posts:
    28
    The issue was fixed and will be available in the next release. Thanks!