【问题标题】:Using/Reading FMOD (.fsb) Files in Java在 Java 中使用/读取 FMOD (.fsb) 文件
【发布时间】:2014-01-04 18:07:40
【问题描述】:

大家好。我目前正在开发一个应该播放 FMOD 数据库中的音乐文件的应用程序。它目前通过将文件(使用运行时和名为“fsbextract.exe”(link)的外部程序)提取为 MP3 然后播放它们来实现。我可以接受,但我现在也很想编辑/替换 .fsb 文件中的文件。所以我的问题是:我可以以某种方式直接访问其中的 MP3 文件而不提取它们吗?我在互联网上搜索了类似的内容,但找不到任何帮助。

作为参考,以下是我可以从 fsbextract 中获得的一些信息:

文件ID 为|FSB4> |版本是 4.0 |条目数 7412

全局标志:

0x40 | FMOD_FSB_SOURCE_MPEG_PADDED4 | MPEG 帧与最接近的 4 个字节对齐,多通道为 16 个字节(使用帧验证选项)

从 fsb 文件中的第一个(索引 0)文件开始: 格式:MP3 (85) 采样率:44100Hz 频道:单声道 持续时间:01.541 比特率:160,62 kbit/s 位/样本 3.64

示例模式标志 [0x10000200] 0x200 | FSOUND_MPEG |样本以 MPEG 格式存储 0x10000000 | FSOUND_MPEG_LAYER3 |样本以 MPEG 第 3 层格式存储

我希望有人比我了解更多,但在此先感谢 马伦休

【问题讨论】:

    标签: java mp3 fmod


    【解决方案1】:

    Jérôme Jouvie 为 FMOD 4+ 编写了一个 JNI 包装器,NativeFmodEx。如果您的 FSB 文件未加密,我认为您可以使用 API 从 FSB 库中提取流数据。

    我也尝试编写自己的包装器,但我没有时间通过​​简单的概念证明。

    更新:当然。所以基本上我所做的是使用JNAerator 来包装本机FMODEx 库,然后将生成的胶水代码定位到BridJ 运行时环境。这实际上允许您调用本机 FMOD C 库。

    我不确定 Jerome 是否做了类似的事情,或者他是否创建了自己的 JNI 存根来实现相同的结果。您必须查看并阅读他的项目代码。

    但本质上,一旦您能够在应用程序中进行 FMOD 调用,您就可以使用 API 随心所欲地进行操作。如果您从 FMOD web site 下载最新的 FMOD studio 或 FMODex SDK,您将找到一个帮助 .chm 文件,其中包含一些 API 文档。

    您还应该查看 SDK 中的示例。

    以下代码基本上是使用上述策略翻译成 Java 的一个示例。代码对于应用程序来说不是可移植的、健壮的或实际有用的。它确实需要清理,但它仍然说明了这一点。

    就像我说的,使用 Jerome 的 SDK 端口应该会更好。

    希望对你有帮助。

    package net.unsungstories.fmodex;
    
    import net.unsungstories.fmodex.FmodexLibrary.FMOD_CHANNEL;
    import net.unsungstories.fmodex.FmodexLibrary.FMOD_SOUND;
    import net.unsungstories.fmodex.FmodexLibrary.FMOD_SYSTEM;
    
    import org.apache.log4j.Logger;
    import org.bridj.IntValuedEnum;
    import org.bridj.Platform;
    import org.bridj.Pointer;
    import org.junit.Test;
    
    import static org.bridj.Pointer.*;
    import static net.unsungstories.fmodex.FmodexLibrary.*;
    import static com.google.common.base.Throwables.*;
    import static java.lang.String.format;
    
    public class PlaySound {
    
        private static final Logger log = Logger.getLogger(PlaySound.class);
    
        @Test
        public void playSound() {
    
            log.info("Test started...");
    
            String soundPath = "./src/test/resources/picus_get_to_finicular_music_0.fsb";
            Platform.addEmbeddedLibraryResourceRoot("net/unsungstories/fmodex/");
    
            IntValuedEnum<FMOD_RESULT> result;
    
            Pointer<Pointer<FMOD_SYSTEM>> ppSystem = allocatePointer(FMOD_SYSTEM.class);
            Pointer<Pointer<FMOD_SOUND>> ppSound1 = allocatePointer(FMOD_SOUND.class);
            Pointer<Integer> pSubSounds = allocateInt();
            Pointer<Pointer<FMOD_CHANNEL>> ppChannel = allocatePointer(FMOD_CHANNEL.class);
    
            @SuppressWarnings("unchecked")
            Pointer<FMOD_CREATESOUNDEXINFO> soundExInfo = Pointer.NULL;
            Pointer<Byte> targetSoundPath = allocateBytes(soundPath.length() + 1);
    
            targetSoundPath.setCString(soundPath);
    
            result = FMOD_System_Create(ppSystem);      
            result = FMOD_System_Init(ppSystem.get(), 2, FmodexLibrary.FMOD_INIT_NORMAL, Pointer.NULL);
            result = FMOD_System_CreateSound(ppSystem.get(), targetSoundPath, FMOD_HARDWARE, soundExInfo, ppSound1);
            result = FMOD_Sound_GetNumSubSounds(ppSound1.get(), pSubSounds);
    
            try {
    
                Pointer<Integer> pChanelPlaying = allocateInt();
    
                for (int k = 0; k < pSubSounds.get(); k++) {
    
                    Pointer<Pointer<FMOD_SOUND>> ppSubSound = allocatePointer(FMOD_SOUND.class); 
    
                    result = FMOD_Sound_GetSubSound(ppSound1.get(), k, ppSubSound);
                    result = FMOD_System_PlaySound(ppSystem.get(), FMOD_CHANNELINDEX.FMOD_CHANNEL_FREE, ppSubSound.get(), 0, ppChannel);
    
                    FMOD_Channel_IsPlaying(ppChannel.get(), pChanelPlaying);
    
                    while (ppChannel.getBoolean()) {
                        log.info("Playing...");                 
                        Thread.sleep(1000);     
                        FMOD_Channel_IsPlaying(ppChannel.get(), pChanelPlaying);
                    }
    
                    result = FMOD_Sound_Release(ppSubSound.get());
                }
    
                result = FMOD_System_Close(ppSystem.get());
                result = FMOD_System_Release(ppSystem.get());
    
            } catch (Exception e) {
                log.error(getStackTraceAsString(getRootCause(e)));
            }       
    
            log.info(format("Finished... %s", result));
        }
    }
    

    希望这会有所帮助。

    【讨论】:

    • 嗯...我真的不知道如何使用它。你能告诉我你制定的概念证明吗?太棒了!
    • 哇,这看起来比我最初想象的要复杂得多。我对编程还是很陌生(2 年了),我真的不明白。如果我现在听起来很愚蠢,我很抱歉,但我想我现在会放弃这个,继续我所得到的和理解的。但真的感谢老兄的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-08
    • 2011-04-30
    • 2017-01-18
    相关资源
    最近更新 更多