5
\$\begingroup\$

I'm trying to make a game with cool soundtracks from a bunch of artists. I've made a few playlists in Soundcloud (soundcloud.com) and am trying to get those to play inside of Unity 3d. Is it possible to do that? I can get a mp3 url from the api but then how do I play it? I'm planning to mac and windows. Please help, thanks! <3

\$\endgroup\$
2
  • 2
    \$\begingroup\$ Can't help on technical side but PLEASE make sure you have legal right to play these songs in your game. \$\endgroup\$
    – Steven
    Dec 9, 2015 at 3:03
  • 1
    \$\begingroup\$ Can u please more elaborate....What have u tried..? \$\endgroup\$ Dec 9, 2015 at 6:54

2 Answers 2

3
\$\begingroup\$

I see you know how to get songs from the API, so i'll skip that part.

If your game is on mobile, you can just get the song with the WWW and use the .GetAudioClip method:

WWW www = new WWW (musicUrl);
while(!www.isDone){
    yield return 0;
}
GetComponent<AudioSource> ().clip = www.GetAudioClip(false, true);

However, if you run your game on PC (and that includes the Unity Editor), you'll get an error:

Streaming of 'mp3' is not supported on this platform.

Apparently, mp3 isn't supported on Desktop, and since SoundCloud's API only serves mp3 files, you'll have to use an external library to decode the mp3 file.

You can download NAudio (documentation here) and follow these steps:

  • In the Unity Editor, select Edit>Project Settings>Player and set the Api Compatibility Level (near the end) to .NET 2.0
  • Add NAudio.dll to your Project's Plugins folder
  • Create a new C# file with the following:

    using UnityEngine;
    using System.IO;
    using System;
    using NAudio;
    using NAudio.Wave;
    
    public static class NAudioPlayer {
        public static AudioClip FromMp3Data(byte[] data)
        {
            // Load the data into a stream
            MemoryStream mp3stream = new MemoryStream(data);
            // Convert the data in the stream to WAV format
            Mp3FileReader mp3audio = new Mp3FileReader(mp3stream);
            WaveStream waveStream = WaveFormatConversionStream.CreatePcmStream(mp3audio);
            // Convert to WAV data
            WAV wav = new WAV(AudioMemStream(waveStream).ToArray());
            Debug.Log(wav);
            AudioClip audioClip = AudioClip.Create("testSound", wav.SampleCount, 1,wav.Frequency, false);
            audioClip.SetData(wav.LeftChannel, 0);
            // Return the clip
            return audioClip;
        }
    
        private static MemoryStream AudioMemStream(WaveStream waveStream)
        {
            MemoryStream outputStream = new MemoryStream();
            using (WaveFileWriter waveFileWriter = new WaveFileWriter(outputStream, waveStream.WaveFormat)) 
            { 
                byte[] bytes = new byte[waveStream.Length]; 
                waveStream.Position = 0;
                waveStream.Read(bytes, 0, Convert.ToInt32(waveStream.Length)); 
                waveFileWriter.Write(bytes, 0, bytes.Length); 
                waveFileWriter.Flush(); 
            }
            return outputStream;
        }
    }
    
    /* From http://answers.unity3d.com/questions/737002/wav-byte-to-audioclip.html */
    public class WAV  {
    
        // convert two bytes to one float in the range -1 to 1
        static float bytesToFloat(byte firstByte, byte secondByte) {
            // convert two bytes to one short (little endian)
            short s = (short)((secondByte << 8) | firstByte);
            // convert to range from -1 to (just below) 1
            return s / 32768.0F;
        }
    
        static int bytesToInt(byte[] bytes,int offset=0){
            int value=0;
            for(int i=0;i<4;i++){
                value |= ((int)bytes[offset+i])<<(i*8);
            }
            return value;
        }
        // properties
        public float[] LeftChannel{get; internal set;}
        public float[] RightChannel{get; internal set;}
        public int ChannelCount {get;internal set;}
        public int SampleCount {get;internal set;}
        public int Frequency {get;internal set;}
    
        public WAV(byte[] wav){
    
            // Determine if mono or stereo
            ChannelCount = wav[22];     // Forget byte 23 as 99.999% of WAVs are 1 or 2 channels
    
            // Get the frequency
            Frequency = bytesToInt(wav,24);
    
            // Get past all the other sub chunks to get to the data subchunk:
            int pos = 12;   // First Subchunk ID from 12 to 16
    
            // Keep iterating until we find the data chunk (i.e. 64 61 74 61 ...... (i.e. 100 97 116 97 in decimal))
            while(!(wav[pos]==100 && wav[pos+1]==97 && wav[pos+2]==116 && wav[pos+3]==97)) {
                pos += 4;
                int chunkSize = wav[pos] + wav[pos + 1] * 256 + wav[pos + 2] * 65536 + wav[pos + 3] * 16777216;
                pos += 4 + chunkSize;
            }
            pos += 8;
    
            // Pos is now positioned to start of actual sound data.
            SampleCount = (wav.Length - pos)/2;     // 2 bytes per sample (16 bit sound mono)
            if (ChannelCount == 2) SampleCount /= 2;        // 4 bytes per sample (16 bit stereo)
    
            // Allocate memory (right will be null if only mono sound)
            LeftChannel = new float[SampleCount];
            if (ChannelCount == 2) RightChannel = new float[SampleCount];
            else RightChannel = null;
    
            // Write to double array/s:
            int i=0;
            while (pos < wav.Length) {
                LeftChannel[i] = bytesToFloat(wav[pos], wav[pos + 1]);
                pos += 2;
                if (ChannelCount == 2) {
                    RightChannel[i] = bytesToFloat(wav[pos], wav[pos + 1]);
                    pos += 2;
                }
                i++;
            }
        }
    
        public override string ToString ()
        {
            return string.Format ("[WAV: LeftChannel={0}, RightChannel={1}, ChannelCount={2}, SampleCount={3}, Frequency={4}]", LeftChannel, RightChannel, ChannelCount, SampleCount, Frequency);
        }
    }
    
  • Use it like this

    WWW www = new WWW (musicUrl);
    while(!www.isDone){
        yield return 0;
    }
    GetComponent<AudioSource> ().clip = NAudioPlayer.FromMp3Data(www.bytes);
    
\$\endgroup\$
1
\$\begingroup\$

I don't think you'd like that. As for today SoundCloud does not have an API for Unity or mobile platforms. I'm not sure but to include their sdk you'd first have to build a library first and experiment A LOT (SO LOT, MUCH LOT, WOW!). Secondly, SoundCloud API's Streaming Sound Docs state you must follow strict guidelines to include their player in your app (or stream it in the app).

In a word - it's tedious. It would be much simpler to create your own server with a bunch of mp3 files in there and download them on request. Advantage of this is that you can keep growing your database even after you launch your game (that's what you need right?). And as @Steven said, make sure it's legal

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .