This is a stream, which allows for playing raw PCM data from a stream.
Inheritance: ISeekableAudioStream
Beispiel #1
0
        public bool StartSpeech(ushort roomNo, ushort localNo)
        {
            if (_cowHeader == null || ServiceLocator.AudioManager == null)
            {
                // TODO: warning("Sound::startSpeech: COW file isn't open");
                return false;
            }

            uint locIndex = 0xFFFFFFFF;
            int sampleSize = 0;
            uint index = 0;

            //            if (_cowMode == CowPSX)
            //            {
            //                Common::File file;
            //                uint16 i;

            //                if (!file.open("speech.lis"))
            //                {
            //                    warning("Could not open speech.lis");
            //                    return false;
            //                }

            //                for (i = 0; !file.eos() && !file.err(); i++)
            //                    if (file.readUint16LE() == roomNo)
            //                    {
            //                        locIndex = i;
            //                        break;
            //                    }
            //                file.close();

            //                if (locIndex == 0xFFFFFFFF)
            //                {
            //                    warning("Could not find room %d in speech.lis", roomNo);
            //                    return false;
            //                }

            //                if (!file.open("speech.inf"))
            //                {
            //                    warning("Could not open speech.inf");
            //                    return false;
            //                }

            //                uint16 numRooms = file.readUint16LE(); // Read number of rooms referenced in this file

            //                file.seek(locIndex * 4 + 2); // 4 bytes per room, skip first 2 bytes

            //                uint16 numLines = file.readUint16LE();
            //                uint16 roomOffset = file.readUint16LE();

            //                file.seek(2 + numRooms * 4 + roomOffset * 2); // The offset is in terms of uint16's, so multiply by 2. Skip the room indexes too.

            //                locIndex = 0xFFFFFFFF;

            //                for (i = 0; i < numLines; i++)
            //                    if (file.readUint16LE() == localNo)
            //                    {
            //                        locIndex = i;
            //                        break;
            //                    }

            //                if (locIndex == 0xFFFFFFFF)
            //                {
            //                    warning("Could not find local number %d in room %d in speech.inf", roomNo, localNo);
            //                    return false;
            //                }

            //                file.close();

            //                index = _cowHeader[(roomOffset + locIndex) * 2];
            //                sampleSize = _cowHeader[(roomOffset + locIndex) * 2 + 1];
            //            }
            //            else {
            locIndex = _cowHeader[roomNo] >> 2;
            sampleSize = (int)_cowHeader[(int)(locIndex + (localNo * 2))];
            index = _cowHeader[(int)(locIndex + (localNo * 2) - 1)];
            //            }

            //            debug(6, "startSpeech(%d, %d): locIndex %d, sampleSize %d, index %d", roomNo, localNo, locIndex, sampleSize, index);

            IAudioStream stream = null;

            if (sampleSize != 0)
            {
                byte speechVol = (byte)((_speechVolR + _speechVolL) / 2);
                sbyte speechPan = (sbyte)((_speechVolR - _speechVolL) / 2);
                if ((_cowMode == CowMode.CowWave) || (_cowMode == CowMode.CowDemo))
                {
                    uint size;
                    var data = UncompressSpeech(index + _cowHeaderSize, (uint)sampleSize, out size);
                    if (data != null)
                    {
                        stream = new RawStream(SPEECH_FLAGS, 11025, true, new MemoryStream(data.Data, data.Offset, (int)size));
                        _speechHandle = _mixer.PlayStream(SoundType.Speech, stream, SOUND_SPEECH_ID, speechVol, speechPan);
                    }
                }
                //                else if (_cowMode == CowPSX && sampleSize != 0xffffffff)
                //                {
                //                    _cowFile.seek(index * 2048);
                //                    Common::SeekableReadStream* tmp = _cowFile.readStream(sampleSize);
                //                    assert(tmp);
                //                    stream = Audio::makeXAStream(tmp, 11025);
                //                    _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, stream, SOUND_SPEECH_ID, speechVol, speechPan);
                //                    // with compressed audio, we can't calculate the wave volume.
                //                    // so default to talking.
                //                    for (int cnt = 0; cnt < 480; cnt++)
                //                        _waveVolume[cnt] = true;
                //                    _waveVolPos = 0;
                //                }
                else if (_cowMode == CowMode.CowFLAC)
                {
                    _cowFile.BaseStream.Seek(index, SeekOrigin.Begin);
                    var tmp = _cowFile.ReadBytes(sampleSize);
                    stream = ServiceLocator.AudioManager.MakeFlacStream(new MemoryStream(tmp));
                    if (stream != null)
                    {
                        _speechHandle = _mixer.PlayStream(SoundType.Speech, stream, SOUND_SPEECH_ID, speechVol, speechPan);
                        // with compressed audio, we can't calculate the wave volume.
                        // so default to talking.
                        for (int cnt = 0; cnt < 480; cnt++)
                            _waveVolume[cnt] = true;
                        _waveVolPos = 0;
                    }
                }
                else if (_cowMode == CowMode.CowVorbis)
                {
                    _cowFile.BaseStream.Seek(index, SeekOrigin.Begin);
                    var tmp = _cowFile.ReadBytes(sampleSize);
                    stream = ServiceLocator.AudioManager.MakeVorbisStream(new MemoryStream(tmp));
                    if (stream != null)
                    {
                        _speechHandle = _mixer.PlayStream(SoundType.Speech, stream, SOUND_SPEECH_ID, speechVol, speechPan);
                        // with compressed audio, we can't calculate the wave volume.
                        // so default to talking.
                        for (int cnt = 0; cnt < 480; cnt++)
                            _waveVolume[cnt] = true;
                        _waveVolPos = 0;
                    }
                }
                else if (_cowMode == CowMode.CowMP3)
                {
                    _cowFile.BaseStream.Seek(index, SeekOrigin.Begin);
                    var tmp = _cowFile.ReadBytes(sampleSize);
                    stream = ServiceLocator.AudioManager.MakeMp3Stream(new MemoryStream(tmp));
                    if (stream != null)
                    {
                        _speechHandle = _mixer.PlayStream(SoundType.Speech, stream, SOUND_SPEECH_ID, speechVol, speechPan);
                        // with compressed audio, we can't calculate the wave volume.
                        // so default to talking.
                        for (int cnt = 0; cnt < 480; cnt++)
                            _waveVolume[cnt] = true;
                        _waveVolPos = 0;
                    }
                }
                return true;
            }
            else
                return false;
        }
Beispiel #2
0
        public void StartChannel(int id, byte[] data, int size, int rate, int vol, int loopStart = 0, int loopEnd = 0, int pan = 0)
        {
            int i;
            if (id == 0)
            {
                Debug.WriteLine("player_mod - attempted to start channel id 0");
            }

            for (i = 0; i < MOD_MAXCHANS; i++)
            {
                if (_channels[i].id == 0)
                    break;
            }
            if (i == MOD_MAXCHANS)
            {
                Debug.WriteLine("player_mod - too many music channels playing ({0} max)", MOD_MAXCHANS);
                return;
            }
            _channels[i].id = id;
            _channels[i].vol = (byte)vol;
            _channels[i].pan = (sbyte)pan;
            _channels[i].freq = (ushort)rate;
            _channels[i].ctr = 0;

            var stream = new RawStream(AudioFlags.None, rate, true, new MemoryStream(data));
            if (loopStart != loopEnd)
            {
                _channels[i].input = new SubLoopingAudioStream(stream, 0, new Timestamp(0, loopStart, rate), new Timestamp(0, loopEnd, rate));
            }
            else
            {
                _channels[i].input = stream;
            }

            // read the first sample
            var sample = new short[1];
            _channels[i].input.ReadBuffer(sample,1);
            _channels[i].pos = sample[0];
        }
Beispiel #3
0
 public void QueueBuffer(byte[] data, int size, bool disposeAfterUse, AudioFlags flags)
 {
     var stream = new RawStream(flags, Rate, disposeAfterUse, new MemoryStream(data, 0, size));
     QueueAudioStream(stream, true);
 }
Beispiel #4
0
        private bool NextPart(ushort[] data, ref int i)
        {
            // return false means cancel intro
            var command = data[i++];
            switch (command)
            {
                case SHOWSCREEN:
                    _skyScreen.ShowScreen(data[i++]);
                    return true;
                case FADEUP:
                    _skyScreen.PaletteFadeUp(data[i++]);
                    _relDelay += 32 * 20; // hack: the screen uses a seperate delay function for the
                                          // blocking fadeups. So add 32*20 msecs to out delay counter.
                    return true;
                case FADEDOWN:
                    _skyScreen.FnFadeDown(0);
                    _relDelay += 32 * 20; // hack: see above.
                    return true;
                case DELAY:
                    if (!EscDelay(data[i++]))
                        return false;
                    return true;
                case DOFLIRT:
                    _skyScreen.StartSequence(data[i++]);
                    while (_skyScreen.SequenceRunning())
                        if (!EscDelay(50))
                            return false;
                    return true;
                case SCROLLFLIRT:
                    return FloppyScrollFlirt();
                case COMMANDFLIRT:
                    return CommandFlirt(data, ref i);
                case STOPFLIRT:
                    _skyScreen.StopSequence();
                    return true;
                case STARTMUSIC:
                    _skyMusic.StartMusic(data[i++]);
                    return true;
                case WAITMUSIC:
                    while (_skyMusic.IsPlaying)
                        if (!EscDelay(50))
                            return false;
                    return true;
                case BGFLIRT:
                    _skyScreen.StartSequence(data[i++]);
                    return true;
                case WAITFLIRT:
                    while (_skyScreen.SequenceRunning())
                        if (!EscDelay(50))
                            return false;
                    return true;
                case PLAYVOICE:
                    {
                        if (!EscDelay(200))
                            return false;
                        var vData = _skyDisk.LoadFile(data[i++]);
                        // HACK: Fill the header with silence. We should
                        // probably use _skySound instead of calling playStream()
                        // directly, but this will have to do for now.
                        vData.Set(0, 127, ServiceLocator.Platform.SizeOf<DataFileHeader>());

                        var stream = new RawStream(AudioFlags.Unsigned, 11025, true, new MemoryStream(vData));
                        _voice = _mixer.PlayStream(SoundType.Speech, stream, Sound.SoundVoice);
                    }
                    return true;
                case WAITVOICE:
                    while (_mixer.IsSoundHandleActive(_voice))
                        if (!EscDelay(50))
                            return false;
                    return true;
                case LOADBG:
                    _mixer.StopID(Sound.SoundBg);
                    _bgBuf = _skyDisk.LoadFile(data[i++]);
                    return true;
                case LOOPBG:
                    {
                        _mixer.StopID(Sound.SoundBg);
                        var stream = new RawStream(AudioFlags.Unsigned, 11025, false, new MemoryStream(_bgBuf, 256, _bgBuf.Length - 768));
                        _bgSfx = _mixer.PlayStream(SoundType.SFX, new LoopingAudioStream(stream, 0), Sound.SoundBg);
                    }
                    return true;
                case PLAYBG:
                    {
                        _mixer.StopID(Sound.SoundBg);
                        var stream = new RawStream(AudioFlags.Unsigned, 11025, false, new MemoryStream(_bgBuf, 256, _bgBuf.Length - 768));
                        _bgSfx = _mixer.PlayStream(SoundType.SFX, stream, Sound.SoundBg);
                    }
                    return true;
                case STOPBG:
                    _mixer.StopID(Sound.SoundBg);
                    return true;
                default:
                    throw new NotSupportedException(string.Format("Unknown intro command {0:X2}", command));
            }
        }
Beispiel #5
0
        public bool StartSpeech(ushort textNum)
        {
            if (!SystemVars.Instance.SystemFlags.HasFlag(SystemFlags.AllowSpeech))
                return false;
            var speechFileNum = (ushort)(_speechConvertTable[textNum >> 12] + (textNum & 0xFFF));

            var speechData = _skyDisk.LoadFile(speechFileNum + 50000);
            if (speechData == null)
            {
                // TODO: debug(9, "File %d (speechFile %d from section %d) wasn't found", speechFileNum + 50000, textNum & 0xFFF, textNum >> 12);
                return false;
            }

            var header = ServiceLocator.Platform.ToStructure<DataFileHeader>(speechData, 0);
            var speechSize = header.s_tot_size - ServiceLocator.Platform.SizeOf<DataFileHeader>();
            var playBuffer = new byte[speechSize];
            Array.Copy(speechData, ServiceLocator.Platform.SizeOf<DataFileHeader>(), playBuffer, 0, speechSize);

            // Workaround for BASS bug #897775 - some voice-overs are played at
            // half speed in 0.0368 (the freeware CD version), in 0.0372 they sound
            // just fine.

            int rate;
            if (_skyDisk.DetermineGameVersion().Version.Minor == 368 && (textNum == 20905 || textNum == 20906))
                rate = 22050;
            else
                rate = 11025;

            _mixer.StopID(SoundSpeech);

            var stream = new RawStream(AudioFlags.Unsigned, rate, true, new MemoryStream(playBuffer, 0, speechSize));
            _ingameSpeech = _mixer.PlayStream(SoundType.Speech, stream, SoundSpeech);
            return true;
        }
Beispiel #6
0
        public void PlaySound(ushort sound, ushort volume, byte channel)
        {
            if (channel == 0)
                _mixer.StopID(SoundChannel0);
            else
                _mixer.StopID(SoundChannel1);

            if (_soundData == null)
            {
                // TODO: warning
                //warning("Sound::playSound(%04X, %04X) called with a section having been loaded", sound, volume);
                return;
            }

            if (sound > _soundsTotal)
            {
                // TODO: debug
                //debug(5, "Sound::playSound %d ignored, only %d sfx in file", sound, _soundsTotal);
                return;
            }

            volume = (ushort)((volume & 0x7F) << 1);
            sound &= 0xFF;

            // Note: All those tables are big endian. Don't ask me why. *sigh*

            // Use the sample rate from game data, see bug #1507757.
            var sampleRate = _sampleRates.Data.ToUInt16BigEndian(_sampleRates.Offset + (sound << 2));
            if (sampleRate > 11025)
                sampleRate = 11025;
            var dataOfs = ScummHelper.SwapBytes(_sfxInfo[((sound << 3) + 0) / 2]) << 4;
            int dataSize = ScummHelper.SwapBytes(_sfxInfo[((sound << 3) + 2) / 2]);
            int dataLoop = ScummHelper.SwapBytes(_sfxInfo[((sound << 3) + 6) / 2]);
            dataOfs += _sfxBaseOfs;

            var stream = new RawStream(AudioFlags.Unsigned, sampleRate, false,
                new MemoryStream(_soundData, dataOfs, dataSize));

            IAudioStream output;
            if (dataLoop != 0)
            {
                var loopSta = dataSize - dataLoop;
                var loopEnd = dataSize;

                output = new SubLoopingAudioStream(stream, 0, new Timestamp(0, loopSta, sampleRate),
                    new Timestamp(0, loopEnd, sampleRate), true);
            }
            else
            {
                output = stream;
            }

            if (channel == 0)
                _ingameSound0 = _mixer.PlayStream(SoundType.SFX, output, SoundChannel0, volume, 0);
            else
                _ingameSound1 = _mixer.PlayStream(SoundType.SFX, output, SoundChannel1, volume, 0);
        }
Beispiel #7
0
        public SoundHandle PlaySound(int id, byte[] sound, int size)
        {
            var flags = AudioFlags.Unsigned;
            var sizeOfDataFileHeader = ServiceLocator.Platform.SizeOf<DataFileHeader>();
            size -= sizeOfDataFileHeader;
            var buffer = new byte[size];
            Array.Copy(sound, sizeOfDataFileHeader, buffer, 0, size);

            _mixer.StopID(id);

            var stream = new RawStream(flags, 11025, true, new MemoryStream(buffer, 0, size));
            return _mixer.PlayStream(SoundType.SFX, stream, id);
        }