Unity 3D音乐播放器

操作系统 云服务/平台 技术难度 关注领域
Android   Intermediate 3D Audio        Gaming

任务目标

音乐使人心情愉悦,带有3D音效的音乐则更能给人带来一种身临其境的感觉,为了实现这种美妙的体验,所以尝试使用高通的3D音频插件基于unity实现一款供自己娱乐的音乐播放器,相信这将会很有趣。

 

这是组成天空盒1的6张背景图。

这是组成天空盒2的6张背景图。

4张图,用作音乐播放器按钮的贴图。

它是音响模型。

所需材料/所需清单/工具

  • Unity 2018.3.9f1 Personal

  • 3D Audio Plugin for Unity

  • Snapdragon Profiler

源码/示例/可执行的应用程序

  • Source Code

附加资料

  • 3DMusicPlayer1.apk

以下展示了在这个项目中使用到的部分。

1. 在带有骁龙845处理器的安卓设备上安装了unity编译的apk,主要用来运行apk并查看3D音乐播放器的效果。

2.windows 7

3.type-c 数据线

4.Unity 2018.3.9f1个人版,所有的开发都是基于Unity。

5.骁龙Profiler,一个用来查看apk实时性能指标的工具。

6.3D音频插件,需要导入到Unity中。

 

部署项目

1.从链接处下载,安装PC。

2. 2. Download Snapdragon Profiler from https://developer.qualcomm.com/software/snapdragon-profiler, and install it to PC.

3. 3. Download 3D Audio Plugin for Unity from https://developer.qualcomm.com/software/3d-audio-plugin-unity, and import into Unity.

4. 寻找按键贴图、音响模型、天空盒资源等,放到Asset子目录下。

5.下载你喜欢的音乐,放到Assets目录下。

6.一步一步实现需要的功能。

7.根据高通提供的步骤试着添加音效。

8.选择android平台,连接设备,然后编译,如果没有问题,将会生成apk并自动安装。

9.打开apk,欣赏它。

10.如果你关注性能指标,你可以使用骁龙Profiler 来查看。

11.如果没有问题,上传代码到github.

 

工作流程

一、开始应该做些什么?

首先,我尝试实现一些基本功能,比如播放、暂停、上一首、下一首、显示正在播放的歌曲信息,因此创建了一个名为MusicPlayer的脚本。

/Assets/Scripts/MusicPlayer.cs

 

using UnityEngine;

using UnityEngine.UI;

 

public class MusicPlayer : MonoBehaviour

{

    private AudioSource audioSource;

    private bool isPlay = false;

    private int audioClipIndex = 0;

 

    public AudioClip[] audioClips;

    public Button previousButton;         //上一首的按键

    public Button nextButton;                //下一首的按键

    public Button playOrPauseButton;  // 播放和暂停按键   

    public Text playOrPauseText;

    public Text MusicNameText;            //歌曲名称

    public Text NowTimeText;                //歌曲当前时间(实际上获取的是   AudioSource的时间)

    public Text FullTimeText;                 //歌曲总时间

    public Slider MusicTimeSlider;        //控制快进或者后退的滑块

 

    public Sprite PausePicture;

    public Sprite PlayPicture;

 

    private int cliphour;

    private int clipminute;

    private int clipsecond;

 

    private int curhour;

    private int curminute;

    private int cursecond;

 

    void Start()

    {

 

        audioSource = GetComponent<AudioSource>();

 

        audioSource.clip = audioClips[audioClipIndex];

        MusicNameText.text = audioClips[audioClipIndex].name;

 

        /* 按下previousButton按键,会给PreviousAudio函数发消息。*/

 

        previousButton.onClick.AddListener(PreviousAudio);   

        nextButton.onClick.AddListener(NextAudio);

        playOrPauseButton.onClick.AddListener(PlayOrPauseAudio);

 

        MusicTimeSlider.onValueChanged.AddListener(

            delegate{

                        setAudioTimeValueChange();

            }

        );

 

}

 

/*更新歌曲信息*/

 

    private void updateMusicInfo()             

    {

        MusicNameText.text = audioClips[audioClipIndex].name;

 

        cliphour = (int) audioSource.clip.length / 3600;

        clipminute = (int) (audioSource.clip.length - cliphour * 3600)/ 60;

        clipsecond = (int) (audioSource.clip.length - cliphour * 3600 - clipminute * 60);

        FullTimeText.text = string.Format("{0:D02}:{1:D2}:{2:D2}", cliphour, clipminute, clipsecond);

}

 

    /*拖动滑块时,UI界面更新滑块值*/

    private void setAudioTimeValueChange()      //改变滑块值;

    {

       //audioSource.time = MusicTimeSlider.value * audioSource.clip.length;

        audioSource.time = MusicTimeSlider.value * audioSource.clip.length;

    }

 

/*按下播放或者暂停按键时的处理逻辑*/

 

    private void PlayOrPauseAudio()

    {

        if (isPlay)

        {

            isPlay = false;

            audioSource.Pause();

            //playOrPauseText.text = "Play";

            playOrPauseButton.GetComponent<Image>().sprite = PausePicture;

        }

        else

        {

            isPlay = true;

            audioSource.Play();

            //playOrPauseText.text = "Pause";

            playOrPauseButton.GetComponent<Image>().sprite = PlayPicture;

        }

    }

 

      /*按下下一首按键时的处理逻辑*/

 

    private void NextAudio()

    {

        audioClipIndex++;

 

        if (audioClipIndex > audioClips.Length - 1)

        {

            audioClipIndex = 0;

        }

 

        if (audioSource.isPlaying == true)

        {

            audioSource.Stop();

        }

 

        audioSource.clip = audioClips[audioClipIndex];

 

        updateMusicInfo();                  //更新歌曲信息

        ShowAudioTIme();

 

        audioSource.Play();

        playOrPauseButton.GetComponent<Image>().sprite = PlayPicture;

    }

 

     /*按上一首按键时的处理逻辑*/

 

    private void PreviousAudio()

    {

        audioClipIndex--;

 

        if (audioClipIndex < 0)

        {

            audioClipIndex = audioClips.Length - 1;

        }

 

        if (audioSource.isPlaying == true)

        {

            audioSource.Stop();

        }

 

        audioSource.clip = audioClips[audioClipIndex];

 

        updateMusicInfo();                  //更新歌曲信息

        ShowAudioTIme();

 

        audioSource.Play();

        playOrPauseButton.GetComponent<Image>().sprite = PlayPicture;

    }

 

/*显示当前时间*/

 

    private void ShowAudioTIme()

    {

        curhour = (int)audioSource.time / 3600;

        curminute = (int)(audioSource.time - curhour * 3600) / 60;

        cursecond = (int)(audioSource.time - curhour * 3600 - curminute * 60);

 

        NowTimeText.text = string.Format("{0:D2}:{1:D2}:{2:D2}", curhour, curminute, cursecond);

        MusicTimeSlider.value = audioSource.time / audioSource.clip.length;

    }

   

/*在每一帧中时间,歌曲信息等*/

 

    void Update()            

    {

        ShowAudioTIme();

        updateMusicInfo();

    }

}

二、如何显示音频数据?

为了实现音频数据可视化,我创建了两个脚本,一个是MakeFreqBands .cs,另外一个是DrawFreqBands.cs

/*平均一定范围内的频谱数据,并赋值给freqBand 数组*/

 

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

 

public class MakeFreqBands : MonoBehaviour

{

    public AudioSource audioSource;

    public static float[] samples = new float[512];

    public static float[] freqBand = new float[8];

    public GameObject prefab;

    GameObject[] MusicCube = new GameObject[512];

 

    // Start is called before the first frame update

    void Start()

    {

        audioSource = GetComponent<AudioSource> ();

    }

 

// Update is called once per frame

 

    void Update()

    {

        GetAudioSourceSpectrum();

        MakefreqBand();

    }

 

    void GetAudioSourceSpectrum()

    {

        audioSource.GetSpectrumData(samples, 0, FFTWindow.Blackman);

    }

 

    void MakefreqBand()

    {

        int count = 0;

        for (int i = 0; i < 8; i++)

        {

            float average = 0;

            int sampleCount = (int)Mathf.Pow(2, i) * 2;         //2^n

            if (i == 7)

            {

                sampleCount += 2;

            }

            for (int j = 0; j < sampleCount; j++)

            {

                average += samples[count] * (count + 1);         //累加2^n以内的频谱数据

                count++;

            }

            average /= count;                                                    //求均值

            freqBand[i] = average * 10;                                  //均值赋给freqBand

        }

    }

}

 

/*根据freqBand值,修改cube的y值以更新cube大小*/

 

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

 

public class DrawFreqBands : MonoBehaviour

{

    public int bandNum;

    public float multiplier, startScale;

 

 

    // Start is called before the first frame update

    void Start()

    {

        //

    }

 

    // Update is called once per frame

    void Update()

    {

        transform.localScale = new Vector3 (transform.localScale.x, (MakeFreqBands.freqBand[bandNum] * multiplier + startScale), transform.localScale.z);

    }

}

三、如何实现手机触控?

为了实现移动音响模型,我添加了一个名为MoveSpeaker.cs的脚本。

using UnityEngine;

using System.Collections;

 

public class MoveSpeaker : MonoBehaviour {

 

    Vector2 m_screenPos = new Vector2(); //记录手指触碰的位置

 

    void Start()

    {

        //Input.multiTouchEnabled = true;//开启多点触碰

    }

    void Update()

    {

        if (Input.touchCount <= 0) 

            return;

        if (Input.touchCount == 1) //单点触碰移动摄像机

        {

            if (Input.touches[0].phase == TouchPhase.Began)

                m_screenPos = Input.touches[0].position;   //记录手指刚触碰的位置

            if (Input.touches[0].phase == TouchPhase.Moved) //手指在屏幕上移动,移动摄像机

            {

                transform.Translate(new Vector3( Input.touches[0].deltaPosition.x * 50 * Time.deltaTime, Input.touches[0].deltaPosition.y * 50 * Time.deltaTime, 0));      

            }

        }

    }

}

四、如何更改和旋转天空盒?

为使得背景看起来更加漂亮,添加了两个脚本,一个是ChangeSkyBox.cs,另外一个是RotateSkyBox.cs

/”设置每过60s更新一个SkyBox”/

 

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

 

public class ChangeSkyBox : MonoBehaviour

{

    /*天空盒数组mats*/

    public Material[] mats;       

    private int index;

    // Start is called before the first frame update

    void Start()

    {

        InvokeRepeating("DoChangeSkyBox", 0, 60f);

    }

 

    void DoChangeSkyBox()

    {

        RenderSettings.skybox = mats[index];

        index++;

        index %= mats.Length;

    }

    void Update()

    {

        //

    }

}

 

 

/*旋转天空盒*/

 

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

 

public class RotateSkyBox : MonoBehaviour

{

    void Start()

    {

       

    }

    void Update()

    {

        float num = RenderSettings.skybox.GetFloat("_Rotation");

        RenderSettings.skybox.SetFloat("_Rotation", num + 0.05f);

    }

}

1、https://github.com/ThunderSoft-XA/Solar-System-With-3D-Sound.git从此链接处下载源码

2、安装unity,unity版本低于5的不可用。(主要是3D音频插件要求unity版本高于5。)

3、双击.unity文件打开demo.

4、编译成apk并安装到安卓设备。

5、打开apk,欣赏它。

6、如果关注性能指标,可以使用骁龙Profiler查看。

贡献者信息

姓名 公司

Zhen

sunzhen@thundersoft.com
Thundersoft

Rong

yangrong0925@thundersoft.com
Thundersoft

Jie

wangjie0508@thundersoft.com
Thundersoft

Kou

kouzw0723@thundersoft.com
Thundersoft

Eric

yansh0810@thundersoft.com
Thundersoft

>>浏览更多Qualcomm硬件案例:http://qualcomm.csdn.net/m/zone/qualcomm2016/project

Qualcomm 解决方案

 

高通软件中心

通过集中式门户站无缝管理您的高通®软件和工具

下载软件中心