Esempio n. 1
0
SharedPtr<Decoder> SndFileDecoderFactory::createDecoder(UniquePtr<std::istream> &file)
{
    SF_VIRTUAL_IO vio = {
        get_filelen, seek,
        read, write, tell
    };
    SF_INFO sndinfo;
    SNDFILE *sndfile = sf_open_virtual(&vio, SFM_READ, &sndinfo, file.get());
    if(!sndfile) return nullptr;

    ChannelConfig sconfig;
    Vector<int> chanmap(sndinfo.channels);
    if(sf_command(sndfile, SFC_GET_CHANNEL_MAP_INFO, &chanmap[0], chanmap.size()*sizeof(int)) == SF_TRUE)
    {
        auto matches = [](const Vector<int> &first, std::initializer_list<int> second) -> bool
        {
            if(first.size() != second.size())
                return false;
            return std::mismatch(first.begin(), first.end(), second.begin()).first == first.end();
        };

        if(matches(chanmap, {SF_CHANNEL_MAP_MONO}))
            sconfig = ChannelConfig::Mono;
        else if(matches(chanmap, {SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT}))
            sconfig = ChannelConfig::Stereo;
        else if(matches(chanmap, {SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT}))
            sconfig = ChannelConfig::Rear;
        else if(matches(chanmap, {SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT,
                                  SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT}))
            sconfig = ChannelConfig::Quad;
        else if(matches(chanmap, {SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT,
                                  SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE,
                                  SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT}) ||
                matches(chanmap, {SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT,
                                  SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE,
                                  SF_CHANNEL_MAP_SIDE_LEFT, SF_CHANNEL_MAP_SIDE_RIGHT}))
            sconfig = ChannelConfig::X51;
        else if(matches(chanmap, {SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT,
                                  SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE,
                                  SF_CHANNEL_MAP_REAR_CENTER, SF_CHANNEL_MAP_SIDE_LEFT,
                                  SF_CHANNEL_MAP_SIDE_RIGHT}))
            sconfig = ChannelConfig::X61;
        else if(matches(chanmap, {SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT,
                                  SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE,
                                  SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT,
                                  SF_CHANNEL_MAP_SIDE_LEFT, SF_CHANNEL_MAP_SIDE_RIGHT}))
            sconfig = ChannelConfig::X71;
        else if(matches(chanmap, {SF_CHANNEL_MAP_AMBISONIC_B_W, SF_CHANNEL_MAP_AMBISONIC_B_X,
                                  SF_CHANNEL_MAP_AMBISONIC_B_Y}))
            sconfig = ChannelConfig::BFormat2D;
        else if(matches(chanmap, {SF_CHANNEL_MAP_AMBISONIC_B_W, SF_CHANNEL_MAP_AMBISONIC_B_X,
                                  SF_CHANNEL_MAP_AMBISONIC_B_Y, SF_CHANNEL_MAP_AMBISONIC_B_Z}))
            sconfig = ChannelConfig::BFormat3D;
        else
        {
            sf_close(sndfile);
            return nullptr;
        }
    }
    else if(sf_command(sndfile, SFC_WAVEX_GET_AMBISONIC, 0, 0) == SF_AMBISONIC_B_FORMAT)
    {
        if(sndinfo.channels == 3)
            sconfig = ChannelConfig::BFormat2D;
        else if(sndinfo.channels == 4)
            sconfig = ChannelConfig::BFormat3D;
        else
        {
            sf_close(sndfile);
            return nullptr;
        }
    }
    else if(sndinfo.channels == 1)
        sconfig = ChannelConfig::Mono;
    else if(sndinfo.channels == 2)
        sconfig = ChannelConfig::Stereo;
    else
    {
        sf_close(sndfile);
        return nullptr;
    }

    SampleType stype = SampleType::Int16;
    switch(sndinfo.format&SF_FORMAT_SUBMASK)
    {
        case SF_FORMAT_FLOAT:
        case SF_FORMAT_DOUBLE:
        case SF_FORMAT_VORBIS:
            stype = SampleType::Float32;
            break;

        default:
            stype = SampleType::Int16;
            break;
    }

    return MakeShared<SndFileDecoder>(std::move(file), sndfile, sndinfo, sconfig, stype);
}
Esempio n. 2
0
SharedPtr<Decoder> SndFileDecoderFactory::createDecoder(SharedPtr<std::istream> file)
{
    SF_VIRTUAL_IO vio = {
        get_filelen, seek,
        read, write, tell
    };
    SF_INFO sndinfo;
    SNDFILE *sndfile = sf_open_virtual(&vio, SFM_READ, &sndinfo, file.get());

    ChannelConfig sconfig;
    if(sndfile)
    {
        Vector<int> chanmap(sndinfo.channels);
        if(sf_command(sndfile, SFC_GET_CHANNEL_MAP_INFO, &chanmap[0], chanmap.size()*sizeof(int)) == SF_TRUE)
        {
            if(sndinfo.channels == 1 && chanmap[0] == SF_CHANNEL_MAP_MONO)
                sconfig = ChannelConfig_Mono;
            else if(sndinfo.channels == 2 &&
                    chanmap[0] == SF_CHANNEL_MAP_LEFT && chanmap[1] == SF_CHANNEL_MAP_RIGHT)
                sconfig = ChannelConfig_Stereo;
            else if(sndinfo.channels == 2 &&
                    chanmap[0] == SF_CHANNEL_MAP_REAR_LEFT && chanmap[1] == SF_CHANNEL_MAP_REAR_RIGHT)
                sconfig = ChannelConfig_Rear;
            else if(sndinfo.channels == 4 &&
                    chanmap[0] == SF_CHANNEL_MAP_LEFT && chanmap[1] == SF_CHANNEL_MAP_RIGHT &&
                    chanmap[2] == SF_CHANNEL_MAP_REAR_LEFT && chanmap[3] == SF_CHANNEL_MAP_REAR_RIGHT)
                sconfig = ChannelConfig_Quad;
            else if(sndinfo.channels == 6 &&
                    chanmap[0] == SF_CHANNEL_MAP_LEFT && chanmap[1] == SF_CHANNEL_MAP_RIGHT &&
                    chanmap[2] == SF_CHANNEL_MAP_CENTER && chanmap[3] == SF_CHANNEL_MAP_LFE &&
                    chanmap[4] == SF_CHANNEL_MAP_REAR_LEFT && chanmap[5] == SF_CHANNEL_MAP_REAR_RIGHT)
                sconfig = ChannelConfig_X51;
            else if(sndinfo.channels == 6 &&
                    chanmap[0] == SF_CHANNEL_MAP_LEFT && chanmap[1] == SF_CHANNEL_MAP_RIGHT &&
                    chanmap[2] == SF_CHANNEL_MAP_CENTER && chanmap[3] == SF_CHANNEL_MAP_LFE &&
                    chanmap[4] == SF_CHANNEL_MAP_SIDE_LEFT && chanmap[5] == SF_CHANNEL_MAP_SIDE_RIGHT)
                sconfig = ChannelConfig_X51;
            else if(sndinfo.channels == 7 &&
                    chanmap[0] == SF_CHANNEL_MAP_LEFT && chanmap[1] == SF_CHANNEL_MAP_RIGHT &&
                    chanmap[2] == SF_CHANNEL_MAP_CENTER && chanmap[3] == SF_CHANNEL_MAP_LFE &&
                    chanmap[4] == SF_CHANNEL_MAP_REAR_CENTER && chanmap[5] == SF_CHANNEL_MAP_SIDE_LEFT &&
                    chanmap[6] == SF_CHANNEL_MAP_SIDE_RIGHT)
                sconfig = ChannelConfig_X61;
            else if(sndinfo.channels == 8 &&
                    chanmap[0] == SF_CHANNEL_MAP_LEFT && chanmap[1] == SF_CHANNEL_MAP_RIGHT &&
                    chanmap[2] == SF_CHANNEL_MAP_CENTER && chanmap[3] == SF_CHANNEL_MAP_LFE &&
                    chanmap[4] == SF_CHANNEL_MAP_REAR_LEFT && chanmap[5] == SF_CHANNEL_MAP_REAR_RIGHT &&
                    chanmap[6] == SF_CHANNEL_MAP_SIDE_LEFT && chanmap[7] == SF_CHANNEL_MAP_SIDE_RIGHT)
                sconfig = ChannelConfig_X51;
            else if(sndinfo.channels == 3 &&
                    chanmap[0] == SF_CHANNEL_MAP_AMBISONIC_B_W && chanmap[1] == SF_CHANNEL_MAP_AMBISONIC_B_X &&
                    chanmap[2] == SF_CHANNEL_MAP_AMBISONIC_B_Y)
                sconfig = ChannelConfig_BFmt_WXY;
            else if(sndinfo.channels == 4 &&
                    chanmap[0] == SF_CHANNEL_MAP_AMBISONIC_B_W && chanmap[1] == SF_CHANNEL_MAP_AMBISONIC_B_X &&
                    chanmap[2] == SF_CHANNEL_MAP_AMBISONIC_B_Y && chanmap[3] == SF_CHANNEL_MAP_AMBISONIC_B_Z)
                sconfig = ChannelConfig_BFmt_WXYZ;
            else
            {
                sf_close(sndfile);
                return 0;
            }
        }
        else if(sf_command(sndfile, SFC_WAVEX_GET_AMBISONIC, 0, 0) == SF_AMBISONIC_B_FORMAT)
        {
            if(sndinfo.channels == 3)
                sconfig = ChannelConfig_BFmt_WXY;
            else if(sndinfo.channels == 4)
                sconfig = ChannelConfig_BFmt_WXYZ;
            else
            {
                sf_close(sndfile);
                return 0;
            }
        }
        else if(sndinfo.channels == 1)
            sconfig = ChannelConfig_Mono;
        else if(sndinfo.channels == 2)
            sconfig = ChannelConfig_Stereo;
        else
        {
            sf_close(sndfile);
            return 0;
        }
    }

    SampleType stype = SampleType_Int16;
    if(sndfile)
    {
        switch(sndinfo.format&SF_FORMAT_SUBMASK)
        {
            case SF_FORMAT_FLOAT:
            case SF_FORMAT_DOUBLE:
            case SF_FORMAT_VORBIS:
                stype = SampleType_Float32;
                break;

            default:
                stype = SampleType_Int16;
                break;
        }
    }

    if(!sndfile) return SharedPtr<Decoder>(nullptr);
    return SharedPtr<Decoder>(new SndFileDecoder(file, sndfile, sndinfo, sconfig, stype));
}