diff --git a/engines/ags/engine/ac/audio_channel.cpp b/engines/ags/engine/ac/audio_channel.cpp index 2adafc4454b..6b8a8c4eb4c 100644 --- a/engines/ags/engine/ac/audio_channel.cpp +++ b/engines/ags/engine/ac/audio_channel.cpp @@ -178,10 +178,17 @@ void AudioChannel_Seek(ScriptAudioChannel *channel, int newPosition) { quitprintf("!AudioChannel.Seek: invalid seek position %d", newPosition); auto *ch = AudioChans::GetChannelIfPlaying(channel->id); - - if (ch) { + if (ch) ch->seek(newPosition); - } +} + +void AudioChannel_SeekMs(ScriptAudioChannel *channel, int newPosition) { + if (newPosition < 0) + quitprintf("!AudioChannel.SeekMs: invalid seek position %d", newPosition); + + auto* ch = AudioChans::GetChannelIfPlaying(channel->id); + if (ch) + ch->seek_ms(newPosition); } void AudioChannel_SetRoomLocation(ScriptAudioChannel *channel, int xPos, int yPos) { @@ -266,6 +273,10 @@ RuntimeScriptValue Sc_AudioChannel_Seek(void *self, const RuntimeScriptValue *pa API_OBJCALL_VOID_PINT(ScriptAudioChannel, AudioChannel_Seek); } +RuntimeScriptValue Sc_AudioChannel_SeekMs(void *self, const RuntimeScriptValue *params, int32_t param_count) { + API_OBJCALL_VOID_PINT(ScriptAudioChannel, AudioChannel_SeekMs); +} + // void | ScriptAudioChannel *channel, int xPos, int yPos RuntimeScriptValue Sc_AudioChannel_SetRoomLocation(void *self, const RuntimeScriptValue *params, int32_t param_count) { API_OBJCALL_VOID_PINT2(ScriptAudioChannel, AudioChannel_SetRoomLocation); @@ -295,6 +306,7 @@ void RegisterAudioChannelAPI() { ccAddExternalObjectFunction("AudioChannel::Pause^0", Sc_AudioChannel_Pause); ccAddExternalObjectFunction("AudioChannel::Resume^0", Sc_AudioChannel_Resume); ccAddExternalObjectFunction("AudioChannel::Seek^1", Sc_AudioChannel_Seek); + ccAddExternalObjectFunction("AudioChannel::SeekMs^1", Sc_AudioChannel_SeekMs); ccAddExternalObjectFunction("AudioChannel::SetRoomLocation^2", Sc_AudioChannel_SetRoomLocation); ccAddExternalObjectFunction("AudioChannel::Stop^0", Sc_AudioChannel_Stop); ccAddExternalObjectFunction("AudioChannel::get_ID", Sc_AudioChannel_GetID); diff --git a/engines/ags/engine/ac/audio_channel.h b/engines/ags/engine/ac/audio_channel.h index 3290a463fc6..a5ea6f8fa36 100644 --- a/engines/ags/engine/ac/audio_channel.h +++ b/engines/ags/engine/ac/audio_channel.h @@ -39,6 +39,7 @@ int AudioChannel_GetVolume(ScriptAudioChannel *channel); int AudioChannel_SetVolume(ScriptAudioChannel *channel, int newVolume); void AudioChannel_Stop(ScriptAudioChannel *channel); void AudioChannel_Seek(ScriptAudioChannel *channel, int newPosition); +void AudioChannel_SeekMs(ScriptAudioChannel *channel, int newPosition); void AudioChannel_SetRoomLocation(ScriptAudioChannel *channel, int xPos, int yPos); } // namespace AGS3 diff --git a/engines/ags/engine/media/audio/clip_my_midi.cpp b/engines/ags/engine/media/audio/clip_my_midi.cpp index b5240de4666..22504f4d557 100644 --- a/engines/ags/engine/media/audio/clip_my_midi.cpp +++ b/engines/ags/engine/media/audio/clip_my_midi.cpp @@ -47,9 +47,14 @@ void MYMIDI::poll() { } void MYMIDI::seek(int pos) { + // pos is the beat number warning("TODO: MYMIDI::seek"); } +void MYMIDI::seek_ms(int pos_ms) { + warning("TODO: MYMIDI::seek_ms"); +} + int MYMIDI::get_pos() { // We don't know ms with midi return 0; diff --git a/engines/ags/engine/media/audio/clip_my_midi.h b/engines/ags/engine/media/audio/clip_my_midi.h index 0d646e60c3f..4b8b36d3f99 100644 --- a/engines/ags/engine/media/audio/clip_my_midi.h +++ b/engines/ags/engine/media/audio/clip_my_midi.h @@ -40,6 +40,7 @@ struct MYMIDI : public SOUNDCLIP { void poll() override; void seek(int pos) override; + void seek_ms(int pos_ms) override; int get_pos() override; diff --git a/engines/ags/engine/media/audio/sound_clip.cpp b/engines/ags/engine/media/audio/sound_clip.cpp index 2ad80703d2e..d669f766aed 100644 --- a/engines/ags/engine/media/audio/sound_clip.cpp +++ b/engines/ags/engine/media/audio/sound_clip.cpp @@ -194,11 +194,19 @@ bool SoundClipWaveBase::is_paused() { } void SoundClipWaveBase::seek(int offset) { + // TODO: for backward compatibility we need to reimplement seeking + // to a position which units are defined according to the sound type: + // - WAV / VOC - the sample number + // - OGG / MP3 - milliseconds + seek_ms(offset); +} + +void SoundClipWaveBase::seek_ms(int pos_ms) { Audio::SeekableAudioStream *stream = dynamic_cast(_stream); if (stream) { - stream->seek(Audio::Timestamp(offset)); + stream->seek(Audio::Timestamp(pos_ms)); } else { warning("Audio stream did not support seeking"); } diff --git a/engines/ags/engine/media/audio/sound_clip.h b/engines/ags/engine/media/audio/sound_clip.h index e02dbb4567f..e752f587a39 100644 --- a/engines/ags/engine/media/audio/sound_clip.h +++ b/engines/ags/engine/media/audio/sound_clip.h @@ -34,6 +34,12 @@ namespace AGS3 { +// SOUNDCLIP's state and parameter updates sync with the audio core in +// batches, only when the engine updates the game, never while the user script +// is being executed. The sync is performed by calling update(). +// This is to ensure that the clip reference, state and properties don't change +// in the middle of the script's command sequence. + // TODO: one of the biggest problems with sound clips currently is that it // provides several methods of applying volume, which may ignore or override // each other, and does not shape a consistent interface. @@ -66,7 +72,21 @@ struct SOUNDCLIP { virtual int play() = 0; virtual void pause() = 0; virtual void resume() = 0; + + /** + * Seeks to the position, where pos units depend on the audio type: + * - MIDI - the beat number + * - MOD / XM / S3M - the pattern number + * - WAV / VOC - the sample number + * - OGG / MP3 - milliseconds + */ virtual void seek(int offset) = 0; + + /** + * Seeks to the position in milliseconds + */ + virtual void seek_ms(int pos_ms) = 0; + virtual int play_from(int position) = 0; virtual bool is_playing() = 0; // true if playing or paused. false if never played or stopped. virtual bool is_paused() = 0; // true if paused @@ -208,6 +228,7 @@ public: bool is_playing() override; bool is_paused() override; void seek(int offset) override; + void seek_ms(int pos_ms) override; int get_pos() override; int get_pos_ms() override; int get_length_ms() override;