Đang tải âm thanh trong XNA mà không có Đường ống nội dung


7

Tôi đang làm việc trên một loại ứng dụng "Game Maker" cho Windows, nơi người dùng nhập tài sản của chính mình để sử dụng trong trò chơi. Tôi cần có thể tải nội dung này trong thời gian chạy ở phía động cơ.

Tuy nhiên, tôi không muốn người dùng phải cài đặt bất cứ thứ gì ngoài thời gian chạy XNA, vì vậy việc gọi đường ống nội dung khi chạy là hết.

Đối với hình ảnh tôi đang làm tốt bằng cách sử dụng Texture2D.FromStream.

Tôi cũng nhận thấy rằng XNA 4.0 đã thêm phương thức FromStream vào lớp SoundEffect nhưng nó chỉ chấp nhận các tệp sóng PCM.

Tôi muốn hỗ trợ nhiều hơn các tệp sóng, ít nhất là MP3.

Có khuyến nghị nào không? Có lẽ một số thư viện C # sẽ thực hiện giải mã sang định dạng sóng PCM.


Điều đáng chú ý là bản thân thời gian chạy XNA không có cách nào giải mã MP3 cho hiệu ứng âm thanh. XNA Game Studio xử lý việc chuyển đổi sang PCM (không nén) hoặc định dạng nén (không phải MP3, nhưng tôi quên chính xác định dạng hiện tại là gì) tại thời điểm xây dựng nội dung. (Mặt khác, âm nhạc được chuyển cho Media Player, có thể phát MP3.)
Andrew Russell

Câu trả lời:


3

Tôi đã không nhận thấy phương pháp FromStream, đó là một cách tốt để nhớ. Bây giờ tôi tò mò về việc sử dụng FromStream vs DynamicSoundEffectInstance, vì về mặt lý thuyết bạn có thể hoàn thành rất nhiều công việc giống nhau với cả hai phương pháp.

Google đã bật thư viện này: http://robburke.net/mle/mp3sharp/ Và bạn cũng có thể gọi lame.exe từ trong ứng dụng của mình để giải mã âm thanh.

Tôi sẽ cảnh giác với MP3 mặc dù, đó là một con giun hợp pháp. Adobe trả một khoản phí khổng lồ cho Fraunhofer để có quyền sử dụng nó trong Flash. Ogg Vorbis là một định dạng ưu việt, dễ dàng chuyển đổi từ mp3 bằng phần mềm miễn phí và nguồn mở và dường như có nhiều thư viện giải mã Net C # /.


Cảm ơn! Tôi đã mơ hồ nhận thức được ý nghĩa pháp lý của việc sử dụng MP3 nhưng điều đó đã xóa nó cho tôi. Tôi sẽ thử các thư viện đó để xem họ có thực sự giải mã được từ MP3 sang OGG hay không (sẽ được thực hiện khi người dùng nhập tài sản) và sau đó từ OGG sang PCM (trong thời gian chạy / tải). Tôi sẽ báo cáo lại với kết quả của mình.
David Gouveia

Các thư viện ogg sẽ không thể, nhưng bạn có thể giải mã với sự khập khiễng sau đó chuyển đổi thành Ogg Vorbis. Chỉ cần không bao gồm LAME và làm như Audacity, "Bạn cần một bộ giải mã mp3, chúng tôi không quan tâm bạn lấy nó ở đâu, chúng tôi có thể biết một nơi để có được nó, nhưng bạn có trách nhiệm phải có được nó". Và từ chối trách nhiệm: Tôi không phải là một luật sư.
michael.bartnett

Tôi vừa nhận thấy rằng SoundEffect.FromStream mong đợi tệp sóng PCM (tiêu đề bao gồm) và một định dạng rất cụ thể. Tôi đã giải mã tệp OGG bằng một trong những thư viện ở trên nhưng dường như tôi không thể để FromStream chấp nhận nó mà không đưa ra một ngoại lệ. Tôi bắt đầu tự hỏi liệu tôi có nên sử dụng API âm thanh bên ngoài như FMOD không.
David Gouveia

Điều đó có thể đáng giá nếu bạn không quan tâm đến việc nhắm mục tiêu Windows Phone hoặc XBLIG. Bạn cũng có thể dùng thử DynamicSoundEffectInstance, nó chỉ đưa ra một sự kiện yêu cầu lấy mẫu mỗi khi nó chạy chậm.
michael.bartnett

1
Tôi thực sự đã sử dụng DynamicSoundEffectInstance để tạo một số thứ khác trước đây (chẳng hạn như cái nàycái này ). :) Nhưng nó cũng yêu cầu bạn gửi các mẫu của bạn ở định dạng rất cụ thể (các mẫu 16 bit xen kẽ), mà tôi không biết đó có phải là định dạng của luồng OGG được giải mã của tôi không. Vì tôi chỉ cần hỗ trợ Windows nên tôi đã đi theo con đường FMOD. Tôi sẽ đăng giải pháp của mình bằng FMOD sau một phút nữa.
David Gouveia

7

Tôi quyết định đưa ra vấn đề này một lần thử hôm nay và cuối cùng đã quản lý để tải một tệp OGG khi chạy vào một SoundEffectđối tượng. Đây là những gì tôi đã làm! Trước tiên hãy tải xuống thư viện bên dưới có chứa một lớp có khả năng giải mã các tệp OGG:

Điều kiện tiên quyết - Tải xuống thư viện

Thư viện đã có một ví dụ, nhưng nó sử dụng DynamicSoundEffectInstancevà truyền phát âm thanh. Nhưng tôi muốn tải tất cả cùng một lúc vào một SoundEffectđối tượng thông thường nên quá trình này hơi khác một chút.

Bước 1 - Giải mã tập tin

Đầu tiên tạo một thể hiện OggDecodervà khởi tạo nó với tệp của bạn:

decoder = new OggDecoder();
decoder.Initialize(TitleContainer.OpenStream(@"sound.ogg"));

Bước 2 - Nhận dữ liệu được giải mã

Đọc tất cả các dữ liệu vào một bộ đệm. Đây là dữ liệu PCM thô được giải mã của tệp:

byte[] data = decoder.SelectMany(chunk => chunk.Bytes.Take(chunk.Length)).ToArray();

Bước 3 - Tạo SoundEffect từ luồng chứa tiêu đề tệp sóng hoàn chỉnh

Tuy nhiên, luồng SoundEffectyêu cầu phải chứa không chỉ dữ liệu thô mà còn cả tiêu đề tệp sóng hoàn chỉnh. Bạn có thể sử dụng phương thức trợ giúp này để viết tiêu đề cộng với dữ liệu:

private static void WriteWave(BinaryWriter writer, int channels, int rate, byte[] data)
{
    writer.Write(new char[4] { 'R', 'I', 'F', 'F' });
    writer.Write((int)(36 + data.Length));
    writer.Write(new char[4] { 'W', 'A', 'V', 'E' });

    writer.Write(new char[4] { 'f', 'm', 't', ' ' });
    writer.Write((int)16);
    writer.Write((short)1);
    writer.Write((short)channels);
    writer.Write((int)rate);
    writer.Write((int)(rate * ((16 * channels) / 8)));
    writer.Write((short)((16 * channels) / 8));
    writer.Write((short)16);

    writer.Write(new char[4] { 'd', 'a', 't', 'a' });
    writer.Write((int)data.Length);
    writer.Write(data);
}

Sử dụng phương pháp đó để ghi dữ liệu vào luồng có thể được cung cấp tới SoundEffect.FromStream:

using (MemoryStream stream = new MemoryStream())
using(BinaryWriter writer = new BinaryWriter(stream))
{
    WriteWave(writer, decoder.Stereo ? 2 : 1, decoder.SampleRate, data);
    stream.Position = 0;
    soundEffect = SoundEffect.FromStream(stream);
}

Bước 4 - Sử dụng SoundEffect như bình thường

Tệp OGG của bạn hiện đã được tải và có thể được sử dụng như mọi tệp khác được SoundEffecttải thông qua đường ống nội dung:

soundEffect.Play();

Hoàn hảo! Ví dụ về trang web không hoạt động chính xác. Tôi đã thử một bài hát với 3:30 phút và nó không phát toàn bộ tập tin. Nhưng giải pháp của bạn đã làm việc hoàn hảo! Nó tải chậm hơn so với ví dụ gốc, nhưng nó có thể được chấp nhận.
Tiểu vương quốc Lima

Liên kết oggsharp nói rằng nó không được dùng nữa và "sử dụng NVorbis" thay vào đó. Có ai đã thử nó chưa? Ngoài ra, sẽ tốt nếu bạn liệt kê rõ ràng "cách sử dụng" (tài liệu tham khảo) cần thiết để làm cho nó hoạt động.
DrZ214

@EmirLima bạn có thể xác nhận nếu bạn đã sử dụng cùng một phiên bản oggsharp như trong liên kết không? Hoặc nếu đó là phiên bản NVorbis mới?
DrZ214

@ DrZ214 Tôi đã sử dụng cùng một phiên bản của trang web. Nhưng giải pháp của David Gouveia hoạt động rất tốt (khởi tạo một SoundEffect với giải mã Ogg).
Tiểu vương quốc Lima

@EmirLima Yea đó chính xác là những gì tôi muốn: SoundEffect được tải với tệp nhạc .ogg. Nơi mà bạn đã nhận được các dll OggSharp? Tại oggsharp.codeplex.com, các nút tải xuống duy nhất tôi có thể tìm thấy cung cấp một tệp zip có ví dụ .exe, không có dlls: /
DrZ214

2

Nếu bạn chỉ nhắm mục tiêu Windows, tôi đã thấy rằng cách dễ nhất là bỏ qua API âm thanh XNA hoàn toàn và sử dụng một cái gì đó khác.

Tôi thấy API FMOD là tuyệt vời cho việc này và thậm chí nó còn đi kèm với trình bao bọc C #. Tôi đã thêm trình bao bọc của riêng mình xung quanh chúng và đây là mức tối thiểu bạn cần để tải âm thanh từ tệp và phát:

Trình bao bọc:

namespace YourNamespace
{
    using System;
    using FMOD;

    public class SoundSystem
    {
        public SoundSystem()
        {
            RESULT result = Factory.System_Create(ref _system);
            if(result != RESULT.OK) 
                throw new Exception("Create SoundSystem Failed");

            uint version = 0;
            result = System.getVersion(ref version);
            if (result != RESULT.OK || version < VERSION.number)
                throw new Exception("Create SoundSystem Failed");

            result = System.init(32, INITFLAGS.NORMAL, (IntPtr)null);
            if (result != RESULT.OK)
                throw new Exception("Create SoundSystem Failed");
        }

        public System System 
        {
            get { return _system; }
        }

        private readonly System _system;
    }

    public class Sound
    {
        public Sound(SoundSystem system, string path)
        {
            _system = system;
            RESULT result = system.System.createSound(path, MODE.HARDWARE, ref _sound);
            if (result != RESULT.OK)
                throw new Exception("Create Sound Failed");
        }

        public void Play()
        {
            Channel channel = null;
            RESULT result = _system.System.playSound(CHANNELINDEX.FREE, _sound, false, ref channel);
            if (result != RESULT.OK)
                throw new Exception("Play Sound Failed");
        }

        private readonly SoundSystem _system;
        private readonly FMOD.Sound _sound;
    }
}

Và làm thế nào để sử dụng nó:

SoundSystem system = new SoundSystem();
Sound sound = new Sound(system, "song.mp3");
sound.Play();

Tất nhiên, trình bao bọc đó chỉ là mức tối thiểu, nhưng nên đơn giản để mở rộng để hiển thị bất kỳ tính năng nào khác bạn cần.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.