• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
Question by DannyB · Nov 17, 2013 at 01:59 PM · audioaudiosourcemusic

Multi Channel Audio

I am trying to figure out what is the best way to have a multi channel song play in Unity.

My use case is simple: I have a song sliced up to different channels (e.g. drums, bass, lead) and I want to play them all in sync, and be able to toggle each channel on or off.

What I have learned so far:

  1. Unity documentation talks about multi channel audio clip, but not in depth.

  2. As far as I understand, a multi channel audio clip must be a tracker module (mod, xm, it, s3m) and I cannot mute/unmute its individual channels.

  3. I was able to successfully play S3M and IT files, but without control over individual channels.

  4. The only working option I found, was to have several audio sources, each with a single channel clip attached. I have some performance, memory and synching concerns with this method.

If anyone has any experience with this, it would be great if you can share.

Comment
jellybit
Nicolaj Schweitz
justinbowes
BanjoSean

People who like this

4 Show 0
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

4 Replies

· Add your reply
  • Sort: 
avatar image

Answer by justinbowes · Mar 18, 2015 at 02:58 PM

I had the same issues, so I brought in a native C# module player (SharpMik) and wired it up as an audio plugin.

For the code that follows, you'll need Unity Singleton, and the source of SharpMik. I put the SharpMik source in Assets/Plugins, deleted some broken module loaders, Naudio and XNA drivers, and some unused WIP source files (effects.cs). Alternately, you could use the included project files to build a DLL. I did not do this as I expect to have to expose some channel mixing functions to Unity at some point.

Save your modules as TextAssets (by adding .bytes to the filename) to bypass Unity's normal module handling.

 using UnityEngine;
 using System;
 using System.Collections;
 using System.IO;
 using SharpMik;
 using SharpMik.Player;
 
 public class SharpModManager : Singleton<SharpModManager> {
 
     internal class UnityVSD : SharpMik.Drivers.VirtualSoftwareDriver {
 
         /**
          * Note: The API for IModDriver has its origins in C APIs where
          * 0 indicates success and nonzero is a specific failure code.
          * 
          * Therefore, functions returning bool return
          *  - true on FAILURE;
          *  - false on SUCCESS.
          */
 
         public AudioSource AudioSource {
             get { return audioSource;}
             set {
                 audioSource = value;
                 applyAudioSource();
             }
         }
 
         AudioSource audioSource { get; set; }
         sbyte[] playerBuffer = new sbyte[0];
         bool playing;
 
         public UnityVSD() {
             m_Name = "Informi SharpMik VSD";
             m_Version = "0.0.1";
             m_HardVoiceLimit = 0;
             m_SoftVoiceLimit = 255;
             m_AutoUpdating = true;
         }
 
         public override void CommandLine(string data) {
             ModDriver.Mode |= SharpMikCommon.DMODE_16BITS;
             ModDriver.Mode |= SharpMikCommon.DMODE_STEREO;
             ModDriver.Mode |= SharpMikCommon.DMODE_INTERP;
 //            ModDriver.Mode |= SharpMikCommon.DMODE_HQMIXER;
 
         }
 
         public override bool IsPresent() {
             int sampleRate = AudioSettings.outputSampleRate;
             if (sampleRate > ushort.MaxValue) {
                 Debug.LogError("Unable to use selected audio source: audio sample rate must be < " + ushort.MaxValue + " (is: " + sampleRate + ")");
                 return false;
             }
             return true;
         }
 
         public override bool Init() {
             if (base.Init()) {
                 Debug.LogError("Underlying virtual driver failed initialization");
                 return true;
             }
 
             ModDriver.MixFreq = (ushort)AudioSettings.outputSampleRate;
             return false;
         }
 
         public override bool PlayStart() {
             playing = !base.PlayStart();
             syncState();
             return !playing;
         }
 
         public override void PlayStop() {
             base.PlayStop();
             playing = false;
             syncState();
         }
 
         public virtual void Mix32f(float[] dataIO, int channelsRequired, float gain) {
             // We force 16-bit mixing, so we're working in 2-byte chunks.
             uint outLen = (uint)dataIO.Length * 2;
             float normalize = gain / 32768f;
             if (playerBuffer.Length < outLen)
                 playerBuffer = new sbyte[outLen];
 
             uint inLen = WriteBytes(playerBuffer, outLen);
             for (uint w = 0, r = 0; r < inLen; ++w, r += 2) {
                 dataIO[w] = ((playerBuffer[r] & 0xff) | (playerBuffer[r + 1] << 8)) * normalize;
             }
         }
 
         void applyAudioSource() {
             syncState();
         }
 
         void syncState() {
             if (playing) {
                 if (audioSource != null) {
                     audioSource.Play();
                 }
             } else {
                 if (audioSource != null) {
                     audioSource.Stop();
                 }
             }
 
         }
     }
 
     [Range(0f, 2f)]
     public float
         FinalGain = 0.75f;
 
     public TextAsset ModuleAsset;
     public bool IsPlaying { get { return player != null && player.IsPlaying(); } }
 
     MikMod player;
     UnityVSD driver;
     Stream songStream;
     TextAsset lastModuleAsset;
 
     void Start() {
         player = new MikMod();
         bool failedInit;
         driver = player.Init<UnityVSD>("command line", out failedInit);
         if (failedInit) {
             player.Exit();
             player = null;
             driver = null;
             return;
         }
 
         driver.AudioSource = Instance.GetOrAddComponent<AudioSource>();
         DontDestroyOnLoad(driver.AudioSource);
     }
 
     void OnAudioFilterRead(float[] dataIO, int channelsRequired) {
         if (player == null || driver == null)
             return;
 
         driver.Mix32f(dataIO, channelsRequired, FinalGain);
     }
 
     void Update() {
         if (lastModuleAsset != ModuleAsset) {
             applyModule(ModuleAsset);                    
             lastModuleAsset = ModuleAsset;
         }
     }
 
     void applyModule(TextAsset apply) {
         if (apply == null) {
             unload();
             return;
         }
 
         if (player == null) {
             Debug.LogError("Cannot play: player failed to initialize");
             return;
         }
         songStream = new MemoryStream(apply.bytes);
         player.Play(songStream);
     }
 
     void unload() {
         player.Stop();
         player.UnLoadCurrent();
         songStream.Close();
     }
 
 
     public void MuteChannel(int channel) {
         if (player == null)
             return;
         player.MuteChannel(channel);
     }
 
     public void UnMuteChannel(int channel) {
         if (player = null)
             return;
         player.UnMuteChannel(channel);
     }
 
 }

This should be sufficient for the use case you describe.

Comment
aka3eka
antonkudin

People who like this

2 Show 0 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image

Answer by aka3eka · Jul 08, 2019 at 08:33 AM

@justinbowes , this is awesome! Works like magic. Thanks a lot for your wrapper code!

Btw there are some bugs in SharpMik though. For example, the method TogglePause() in MikMod.cs should call ModPlayer.Player_TogglePause();, not ModPlayer.Player_Paused();. And of course, ModPlayer.cs is a real spaghetti code ;) But it works!

I also added a few methods to control playback speed (bpm), volume, etc. and it works just fine.

Comment
dfarjoun

People who like this

1 Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image dfarjoun · Nov 10, 2019 at 11:30 AM 0
Share

Is it possible to share this working/corrected code? I'm learning programming, so I think it will be hard to figure out how to fix everything for now (but I have a huge background in audio/mixing) :) I'm struggling to have multiple audio files playing in sync. When they play in sync I have buffer problems with crackling slowed down play. When I remove the sync they play good, but don't work for my purpose. :(

avatar image

Answer by mdahlgrengadd · Oct 17, 2018 at 10:30 PM

Thanks! This still works very well! Had to comment out all debug messages in the code too, though.

Comment

People who like this

0 Show 0 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image

Answer by derekstutsman · May 02, 2022 at 07:28 PM

Does playing the audio in this fashion burn a lot of CPU?

I also want to shift between synchronized tracks but thought it might be passable to just have multiple versions of the same song mp3 and swap at the same play position.

Comment

People who like this

0 Show 0 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

22 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

AudioSource.Pause not working? 3 Answers

How would I go about using music from StreamingAssets folder (imported by the player) 0 Answers

How to stop music from restarting when reloading scene it began? 0 Answers

Audio Manager or not? Audio System 0 Answers

C sharp cant play Audio 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges