diff --git a/Content/Documentation/ScriptingAPI-Documentation.md b/Content/Documentation/ScriptingAPI-Documentation.md index 47e2bfc14..d94e5c494 100644 --- a/Content/Documentation/ScriptingAPI-Documentation.md +++ b/Content/Documentation/ScriptingAPI-Documentation.md @@ -407,9 +407,22 @@ An audio file. Can be instanced several times via SoundInstance. - [constructor]Sound() -- creates an empty sound. Use the audio device to load sounds from files #### SoundInstance -An audio file instance that can be played. +An audio file instance that can be played. Note: after modifying parameters of the SoundInstance, the SoundInstance will need to be recreated from a specified sound - [constructor]SoundInstance() -- creates an empty soundinstance. Use the audio device to clone sounds - SetSubmixType(int submixtype) -- set a submix type group (default is SUBMIX_TYPE_SOUNDEFFECT) +- SetBegin(float seconds) -- beginning of the playback in seconds, relative to the Sound it will be created from (0 = from beginning) +- SetLength(float seconds) -- length in seconds (0 = until end) +- SetLoopBegin(float seconds) -- loop region begin in seconds, relative to the instance begin time (0 = from beginning) +- SetLoopLength(float seconds) -- loop region length in seconds (0 = until the end) +- SetEnableReverb(bool value) -- enable/disable reverb for the sound instance +- SetLooped(bool value) -- enable/disable looping for the sound instance +- GetSubmixType() : int +- GetBegin() : float +- GetLength() : float +- GetLoopBegin() : float +- GetLoopLength() : float +- IsEnableReverb() : bool +- IsLooped() : bool #### SoundInstance3D Describes the relation between a sound instance and a listener in a 3D world @@ -1434,6 +1447,7 @@ Query input devices - [void-constructor]Input() - Down(int code, opt int playerindex = 0) : bool result -- Check whether a button is currently being held down - Press(int code, opt int playerindex = 0) : bool result -- Check whether a button has just been pushed that wasn't before +- Release(int code, opt int playerindex = 0) : bool result -- Check whether a button has just been released that was down before - Hold(int code, opt int duration = 30, opt boolean continuous = false, opt int playerindex = 0) : bool result -- Check whether a button was being held down for a specific duration (nunmber of frames). If continuous == true, than it will also return true after the duration was reached - GetPointer() : Vector result -- get mouse pointer or primary touch position (x, y). Also returns mouse wheel delta movement (z), and pen pressure (w) - SetPointer(Vector pos) -- set mouse poisition diff --git a/Editor/SoundWindow.cpp b/Editor/SoundWindow.cpp index 8cd40cbe9..1a449926f 100644 --- a/Editor/SoundWindow.cpp +++ b/Editor/SoundWindow.cpp @@ -35,7 +35,7 @@ void SoundWindow::Create(EditorComponent* _editor) { editor = _editor; wi::gui::Window::Create(ICON_SOUND " Sound", wi::gui::Window::WindowControls::COLLAPSE | wi::gui::Window::WindowControls::CLOSE); - SetSize(XMFLOAT2(440, 300)); + SetSize(XMFLOAT2(440, 400)); closeButton.SetTooltip("Delete SoundComponent"); OnClose([=](wi::gui::EventArgs args) { @@ -106,7 +106,7 @@ void SoundWindow::Create(EditorComponent* _editor) playstopButton.SetText(ICON_STOP); } } - }); + }); AddWidget(&playstopButton); playstopButton.SetEnabled(false); @@ -121,7 +121,7 @@ void SoundWindow::Create(EditorComponent* _editor) { sound->SetLooped(args.bValue); } - }); + }); AddWidget(&loopedCheckbox); loopedCheckbox.SetEnabled(false); @@ -136,7 +136,7 @@ void SoundWindow::Create(EditorComponent* _editor) sound->soundinstance.SetEnableReverb(args.bValue); wi::audio::CreateSoundInstance(&sound->soundResource.GetSound(), &sound->soundinstance); } - }); + }); AddWidget(&reverbCheckbox); reverbCheckbox.SetEnabled(false); @@ -149,9 +149,8 @@ void SoundWindow::Create(EditorComponent* _editor) if (sound != nullptr) { sound->SetDisable3D(args.bValue); - wi::audio::CreateSoundInstance(&sound->soundResource.GetSound(), &sound->soundinstance); } - }); + }); AddWidget(&disable3dCheckbox); loopedCheckbox.SetEnabled(false); @@ -165,7 +164,7 @@ void SoundWindow::Create(EditorComponent* _editor) { sound->volume = args.fValue; } - }); + }); AddWidget(&volumeSlider); volumeSlider.SetEnabled(false); @@ -179,7 +178,7 @@ void SoundWindow::Create(EditorComponent* _editor) sound->soundinstance.type = (wi::audio::SUBMIX_TYPE)args.iValue; wi::audio::CreateSoundInstance(&sound->soundResource.GetSound(), &sound->soundinstance); } - }); + }); submixComboBox.AddItem("SOUNDEFFECT"); submixComboBox.AddItem("MUSIC"); submixComboBox.AddItem("USER0"); @@ -231,6 +230,61 @@ void SoundWindow::Create(EditorComponent* _editor) waveGraph.SetSize(XMFLOAT2(100, 50)); AddWidget(&waveGraph); + beginInput.Create(""); + beginInput.SetDescription("Begin: "); + beginInput.SetTooltip("Beginning of the playback in seconds, relative to the Sound it will be created from (0 = from beginning)."); + beginInput.SetSize(XMFLOAT2(wid, hei)); + beginInput.OnInputAccepted([&](wi::gui::EventArgs args) { + SoundComponent* sound = editor->GetCurrentScene().sounds.GetComponent(entity); + if (sound != nullptr) + { + sound->soundinstance.begin = args.fValue; + wi::audio::CreateSoundInstance(&sound->soundResource.GetSound(), &sound->soundinstance); + } + }); + AddWidget(&beginInput); + + lengthInput.Create(""); + lengthInput.SetDescription("Length: "); + lengthInput.SetTooltip("Length in seconds (0 = until end)"); + lengthInput.SetSize(XMFLOAT2(wid, hei)); + lengthInput.OnInputAccepted([&](wi::gui::EventArgs args) { + SoundComponent* sound = editor->GetCurrentScene().sounds.GetComponent(entity); + if (sound != nullptr) + { + sound->soundinstance.length = args.fValue; + wi::audio::CreateSoundInstance(&sound->soundResource.GetSound(), &sound->soundinstance); + } + }); + AddWidget(&lengthInput); + + loopBeginInput.Create(""); + loopBeginInput.SetDescription("Loop Begin: "); + loopBeginInput.SetTooltip("Loop region begin in seconds, relative to the instance begin time (0 = from beginning)"); + loopBeginInput.SetSize(XMFLOAT2(wid, hei)); + loopBeginInput.OnInputAccepted([&](wi::gui::EventArgs args) { + SoundComponent* sound = editor->GetCurrentScene().sounds.GetComponent(entity); + if (sound != nullptr) + { + sound->soundinstance.loop_begin = args.fValue; + wi::audio::CreateSoundInstance(&sound->soundResource.GetSound(), &sound->soundinstance); + } + }); + AddWidget(&loopBeginInput); + + loopLengthInput.Create(""); + loopLengthInput.SetDescription("Loop Length: "); + loopLengthInput.SetTooltip("Loop region length in seconds (0 = until the end)"); + loopLengthInput.SetSize(XMFLOAT2(wid, hei)); + loopLengthInput.OnInputAccepted([&](wi::gui::EventArgs args) { + SoundComponent* sound = editor->GetCurrentScene().sounds.GetComponent(entity); + if (sound != nullptr) + { + sound->soundinstance.loop_length = args.fValue; + wi::audio::CreateSoundInstance(&sound->soundResource.GetSound(), &sound->soundinstance); + } + }); + AddWidget(&loopLengthInput); SetMinimized(true); SetVisible(false); @@ -277,35 +331,38 @@ void WaveGraph::Render(const wi::Canvas& canvas, wi::graphics::CommandList cmd) { // Vertices for [-1, 1] second range of current sound sample: wi::audio::SampleInfo info = wi::audio::GetSampleInfo(&sound->soundResource.GetSound()); - uint32_t sample_frequency = info.sample_rate * info.channel_count; - uint32_t step = uint32_t(sample_frequency * 2) / vertexCount; - uint64_t current_sample = wi::audio::GetTotalSamplesPlayed(&sound->soundinstance); + const uint32_t step = uint32_t(info.sample_rate * 2) / vertexCount; + const uint32_t instance_sample_offset = uint32_t(sound->soundinstance.begin * info.sample_rate); + const uint32_t instance_sample_count = uint32_t(sound->soundinstance.length > 0 ? uint32_t(sound->soundinstance.length * info.sample_rate) : uint32_t(info.sample_count)); + uint64_t current_instance_sample = wi::audio::GetTotalSamplesPlayed(&sound->soundinstance); if (sound->IsLooped()) { - float total_time = float(current_sample) / float(info.sample_rate); + float total_time = float(current_instance_sample) / float(info.sample_rate); if (total_time > sound->soundinstance.loop_begin) { - float loop_length = sound->soundinstance.loop_length > 0 ? sound->soundinstance.loop_length : (float(info.sample_count) / float(sample_frequency)); + float loop_length = sound->soundinstance.loop_length > 0 ? sound->soundinstance.loop_length : (float(info.sample_count) / float(info.sample_rate)); float loop_time = std::fmod(total_time - sound->soundinstance.loop_begin, loop_length); - current_sample = uint64_t(loop_time * info.sample_rate); + current_instance_sample = uint64_t(loop_time * info.sample_rate); } } - current_sample *= info.channel_count; + current_instance_sample = current_instance_sample % instance_sample_count; + + uint64_t current_sound_sample = instance_sample_offset + current_instance_sample; // This integer divide and multiply fixes the sample positions so the wave visualizer is stable: - current_sample /= step; - current_sample *= step; - int64_t start_sample = (int64_t)current_sample - sample_frequency; - int64_t end_sample = current_sample + sample_frequency; + current_sound_sample /= step; + current_sound_sample *= step; + int64_t start_sample = (int64_t)current_sound_sample - info.sample_rate; + int64_t end_sample = current_sound_sample + info.sample_rate; Vertex vert; vert.color = base_color; for (uint32_t i = 0; i < vertexCount; ++i) { vert.position = XMFLOAT4(float(i) / vertexCount, 0, 0, 1); - int64_t sample_idx = start_sample + i * step; + const int64_t sample_idx = start_sample + i * step; if (sample_idx > 0 && sample_idx < (int64_t)info.sample_count) { - vert.position.y = float(info.samples[sample_idx]) / 32768.0f; + vert.position.y = float(info.samples[sample_idx * info.channel_count]) / 32768.0f; } std::memcpy((Vertex*)allocation.data + i, &vert, sizeof(vert)); } @@ -407,6 +464,10 @@ void SoundWindow::SetEntity(Entity entity) { submixComboBox.SetSelected((int)sound->soundinstance.type); } + beginInput.SetValue(sound->soundinstance.begin); + lengthInput.SetValue(sound->soundinstance.length); + loopBeginInput.SetValue(sound->soundinstance.loop_begin); + loopLengthInput.SetValue(sound->soundinstance.loop_length); } else { @@ -432,7 +493,7 @@ void SoundWindow::ResizeLayout() auto add = [&](wi::gui::Widget& widget) { if (!widget.IsVisible()) return; - const float margin_left = 80; + const float margin_left = 100; const float margin_right = 40; widget.SetPos(XMFLOAT2(margin_left, y)); widget.SetSize(XMFLOAT2(width - margin_left - margin_right, widget.GetScale().y)); @@ -468,6 +529,11 @@ void SoundWindow::ResizeLayout() add(submixComboBox); add(reverbComboBox); + add(beginInput); + add(lengthInput); + add(loopBeginInput); + add(loopLengthInput); + y += 10; add_fullwidth(waveGraph); } diff --git a/Editor/SoundWindow.h b/Editor/SoundWindow.h index 0ae763454..225c56b26 100644 --- a/Editor/SoundWindow.h +++ b/Editor/SoundWindow.h @@ -27,6 +27,10 @@ public: wi::gui::CheckBox disable3dCheckbox; wi::gui::Slider volumeSlider; wi::gui::ComboBox submixComboBox; + wi::gui::TextInputField beginInput; + wi::gui::TextInputField lengthInput; + wi::gui::TextInputField loopBeginInput; + wi::gui::TextInputField loopLengthInput; WaveGraph waveGraph; void ResizeLayout() override; diff --git a/WickedEngine/wiAudio.cpp b/WickedEngine/wiAudio.cpp index 308efadb7..d89073bb3 100644 --- a/WickedEngine/wiAudio.cpp +++ b/WickedEngine/wiAudio.cpp @@ -426,12 +426,30 @@ namespace wi::audio instanceinternal->channelAzimuths[i] = X3DAUDIO_2PI * float(i) / float(instanceinternal->channelAzimuths.size()); } - instanceinternal->buffer.AudioBytes = (UINT32)soundinternal->audioData.size(); + const uint32_t bytes_per_second = soundinternal->wfx.nSamplesPerSec * soundinternal->wfx.nChannels * sizeof(short); instanceinternal->buffer.pAudioData = soundinternal->audioData.data(); + instanceinternal->buffer.AudioBytes = (uint32_t)soundinternal->audioData.size(); + if (instance->begin > 0) + { + const uint32_t bytes_from_beginning = std::min(instanceinternal->buffer.AudioBytes, uint32_t(instance->begin * bytes_per_second)); + instanceinternal->buffer.pAudioData += bytes_from_beginning; + instanceinternal->buffer.AudioBytes -= bytes_from_beginning; + } + if (instance->length > 0) + { + instanceinternal->buffer.AudioBytes = std::min(instanceinternal->buffer.AudioBytes, uint32_t(instance->length * bytes_per_second)); + } + + uint32_t num_remaining_samples = instanceinternal->buffer.AudioBytes / (soundinternal->wfx.nChannels * sizeof(short)); + if (instance->loop_begin > 0) + { + instanceinternal->buffer.LoopBegin = std::min(num_remaining_samples, uint32_t(instance->loop_begin * soundinternal->wfx.nSamplesPerSec)); + num_remaining_samples -= instanceinternal->buffer.LoopBegin; + } + instanceinternal->buffer.LoopLength = std::min(num_remaining_samples, uint32_t(instance->loop_length * soundinternal->wfx.nSamplesPerSec)); + instanceinternal->buffer.Flags = XAUDIO2_END_OF_STREAM; - instanceinternal->buffer.LoopCount = XAUDIO2_LOOP_INFINITE; - instanceinternal->buffer.LoopBegin = UINT32(instance->loop_begin * instanceinternal->audio->masteringVoiceDetails.InputSampleRate); - instanceinternal->buffer.LoopLength = UINT32(instance->loop_length * instanceinternal->audio->masteringVoiceDetails.InputSampleRate); + instanceinternal->buffer.LoopCount = instance->IsLooped() ? XAUDIO2_LOOP_INFINITE : 0; hr = instanceinternal->sourceVoice->SubmitSourceBuffer(&instanceinternal->buffer); if (FAILED(hr)) @@ -539,10 +557,10 @@ namespace wi::audio if (sound != nullptr && sound->IsValid()) { auto soundinternal = to_internal(sound); - info.samples = (const short*)soundinternal->audioData.data(); - info.sample_count = soundinternal->audioData.size() / sizeof(short); - info.sample_rate = soundinternal->wfx.nSamplesPerSec; info.channel_count = soundinternal->wfx.nChannels; + info.samples = (const short*)soundinternal->audioData.data(); + info.sample_count = soundinternal->audioData.size() / (info.channel_count * sizeof(short)); + info.sample_rate = soundinternal->wfx.nSamplesPerSec; } return info; } @@ -988,12 +1006,30 @@ namespace wi::audio instanceinternal->channelAzimuths[i] = F3DAUDIO_2PI * float(i) / float(instanceinternal->channelAzimuths.size()); } - instanceinternal->buffer.AudioBytes = (uint32_t)soundinternal->audioData.size(); + const uint32_t bytes_per_second = soundinternal->wfx.nSamplesPerSec * soundinternal->wfx.nChannels * sizeof(short); instanceinternal->buffer.pAudioData = soundinternal->audioData.data(); + instanceinternal->buffer.AudioBytes = (uint32_t)soundinternal->audioData.size(); + if (instance->begin > 0) + { + const uint32_t bytes_from_beginning = std::min(instanceinternal->buffer.AudioBytes, uint32_t(instance->begin * bytes_per_second)); + instanceinternal->buffer.pAudioData += bytes_from_beginning; + instanceinternal->buffer.AudioBytes -= bytes_from_beginning; + } + if (instance->length > 0) + { + instanceinternal->buffer.AudioBytes = std::min(instanceinternal->buffer.AudioBytes, uint32_t(instance->length * bytes_per_second)); + } + + uint32_t num_remaining_samples = instanceinternal->buffer.AudioBytes / (soundinternal->wfx.nChannels * sizeof(short)); + if (instance->loop_begin > 0) + { + instanceinternal->buffer.LoopBegin = std::min(num_remaining_samples, uint32_t(instance->loop_begin * soundinternal->wfx.nSamplesPerSec)); + num_remaining_samples -= instanceinternal->buffer.LoopBegin; + } + instanceinternal->buffer.LoopLength = std::min(num_remaining_samples, uint32_t(instance->loop_length * soundinternal->wfx.nSamplesPerSec)); + instanceinternal->buffer.Flags = FAUDIO_END_OF_STREAM; - instanceinternal->buffer.LoopCount = FAUDIO_LOOP_INFINITE; - instanceinternal->buffer.LoopBegin = uint32_t(instance->loop_begin * instanceinternal->audio->masteringVoiceDetails.InputSampleRate); - instanceinternal->buffer.LoopLength = uint32_t(instance->loop_length * instanceinternal->audio->masteringVoiceDetails.InputSampleRate); + instanceinternal->buffer.LoopCount = instance->IsLooped() ? FAUDIO_LOOP_INFINITE : 0; res = FAudioSourceVoice_SubmitSourceBuffer(instanceinternal->sourceVoice, &(instanceinternal->buffer), nullptr); if(res != 0){ diff --git a/WickedEngine/wiAudio.h b/WickedEngine/wiAudio.h index a744101c8..65bad3c4c 100644 --- a/WickedEngine/wiAudio.h +++ b/WickedEngine/wiAudio.h @@ -39,19 +39,26 @@ namespace wi::audio std::shared_ptr internal_state; inline bool IsValid() const { return internal_state.get() != nullptr; } + // You can specify these params before creating the sound instance: + // The sound instance will need to be recreated for changes to take effect SUBMIX_TYPE type = SUBMIX_TYPE_SOUNDEFFECT; - float loop_begin = 0; // loop region begin in seconds (0 = from beginning) + float begin = 0; // beginning of the playback in seconds, relative to the Sound it will be created from (0 = from beginning) + float length = 0; // length in seconds (0 = until end) + float loop_begin = 0; // loop region begin in seconds, relative to the instance begin time (0 = from beginning) float loop_length = 0; // loop region length in seconds (0 = until the end) enum FLAGS { EMPTY = 0, ENABLE_REVERB = 1 << 0, + LOOPED = 1 << 1, }; uint32_t _flags = EMPTY; inline void SetEnableReverb(bool value = true) { if (value) { _flags |= ENABLE_REVERB; } else { _flags &= ~ENABLE_REVERB; } } inline bool IsEnableReverb() const { return _flags & ENABLE_REVERB; } + inline void SetLooped(bool value = true) { if (value) { _flags |= LOOPED; } else { _flags &= ~LOOPED; } } + inline bool IsLooped() const { return _flags & LOOPED; } }; bool CreateSound(const std::string& filename, Sound* sound); diff --git a/WickedEngine/wiAudio_BindLua.cpp b/WickedEngine/wiAudio_BindLua.cpp index e40ca0e1f..5ed986870 100644 --- a/WickedEngine/wiAudio_BindLua.cpp +++ b/WickedEngine/wiAudio_BindLua.cpp @@ -309,6 +309,19 @@ REVERB_PRESET_PLATE = 29 Luna::FunctionType SoundInstance_BindLua::methods[] = { lunamethod(SoundInstance_BindLua, SetSubmixType), + lunamethod(SoundInstance_BindLua, SetBegin), + lunamethod(SoundInstance_BindLua, SetLength), + lunamethod(SoundInstance_BindLua, SetLoopBegin), + lunamethod(SoundInstance_BindLua, SetLoopLength), + lunamethod(SoundInstance_BindLua, SetEnableReverb), + lunamethod(SoundInstance_BindLua, SetLooped), + lunamethod(SoundInstance_BindLua, GetSubmixType), + lunamethod(SoundInstance_BindLua, GetBegin), + lunamethod(SoundInstance_BindLua, GetLength), + lunamethod(SoundInstance_BindLua, GetLoopBegin), + lunamethod(SoundInstance_BindLua, GetLoopLength), + lunamethod(SoundInstance_BindLua, IsEnableReverb), + lunamethod(SoundInstance_BindLua, IsLooped), { NULL, NULL } }; Luna::PropertyType SoundInstance_BindLua::properties[] = { @@ -327,6 +340,107 @@ REVERB_PRESET_PLATE = 29 wi::lua::SError(L, "SetSubmixType(int submixtype) not enough arguments!"); return 0; } + int SoundInstance_BindLua::SetBegin(lua_State* L) + { + int argc = wi::lua::SGetArgCount(L); + if (argc > 0) + { + soundinstance.begin = wi::lua::SGetFloat(L, 1); + } + else + wi::lua::SError(L, "SetBegin(float seconds) not enough arguments!"); + return 0; + } + int SoundInstance_BindLua::SetLength(lua_State* L) + { + int argc = wi::lua::SGetArgCount(L); + if (argc > 0) + { + soundinstance.length = wi::lua::SGetFloat(L, 1); + } + else + wi::lua::SError(L, "SetLength(float seconds) not enough arguments!"); + return 0; + } + int SoundInstance_BindLua::SetLoopBegin(lua_State* L) + { + int argc = wi::lua::SGetArgCount(L); + if (argc > 0) + { + soundinstance.loop_begin = wi::lua::SGetFloat(L, 1); + } + else + wi::lua::SError(L, "SetLoopBegin(float seconds) not enough arguments!"); + return 0; + } + int SoundInstance_BindLua::SetLoopLength(lua_State* L) + { + int argc = wi::lua::SGetArgCount(L); + if (argc > 0) + { + soundinstance.loop_length = wi::lua::SGetFloat(L, 1); + } + else + wi::lua::SError(L, "SetLoopLength(float seconds) not enough arguments!"); + return 0; + } + int SoundInstance_BindLua::SetEnableReverb(lua_State* L) + { + int argc = wi::lua::SGetArgCount(L); + if (argc > 0) + { + soundinstance.SetEnableReverb(wi::lua::SGetBool(L, 1)); + } + else + wi::lua::SError(L, "SetEnableReverb(bool value) not enough arguments!"); + return 0; + } + int SoundInstance_BindLua::SetLooped(lua_State* L) + { + int argc = wi::lua::SGetArgCount(L); + if (argc > 0) + { + soundinstance.SetLooped(wi::lua::SGetBool(L, 1)); + } + else + wi::lua::SError(L, "SetLooped(bool value) not enough arguments!"); + return 0; + } + int SoundInstance_BindLua::GetSubmixType(lua_State* L) + { + wi::lua::SSetInt(L, (int)soundinstance.type); + return 1; + } + int SoundInstance_BindLua::GetBegin(lua_State* L) + { + wi::lua::SSetFloat(L, soundinstance.begin); + return 1; + } + int SoundInstance_BindLua::GetLength(lua_State* L) + { + wi::lua::SSetFloat(L, soundinstance.length); + return 1; + } + int SoundInstance_BindLua::GetLoopBegin(lua_State* L) + { + wi::lua::SSetFloat(L, soundinstance.loop_begin); + return 1; + } + int SoundInstance_BindLua::GetLoopLength(lua_State* L) + { + wi::lua::SSetFloat(L, soundinstance.loop_length); + return 1; + } + int SoundInstance_BindLua::IsEnableReverb(lua_State* L) + { + wi::lua::SSetBool(L, soundinstance.IsEnableReverb()); + return 1; + } + int SoundInstance_BindLua::IsLooped(lua_State* L) + { + wi::lua::SSetBool(L, soundinstance.IsLooped()); + return 1; + } void SoundInstance_BindLua::Bind() { diff --git a/WickedEngine/wiAudio_BindLua.h b/WickedEngine/wiAudio_BindLua.h index 6907ce558..c6b84baa1 100644 --- a/WickedEngine/wiAudio_BindLua.h +++ b/WickedEngine/wiAudio_BindLua.h @@ -60,6 +60,20 @@ namespace wi::lua ~SoundInstance_BindLua() { } int SetSubmixType(lua_State* L); + int SetBegin(lua_State* L); + int SetLength(lua_State* L); + int SetLoopBegin(lua_State* L); + int SetLoopLength(lua_State* L); + int SetEnableReverb(lua_State* L); + int SetLooped(lua_State* L); + + int GetSubmixType(lua_State* L); + int GetBegin(lua_State* L); + int GetLength(lua_State* L); + int GetLoopBegin(lua_State* L); + int GetLoopLength(lua_State* L); + int IsEnableReverb(lua_State* L); + int IsLooped(lua_State* L); static void Bind(); }; diff --git a/WickedEngine/wiInput.cpp b/WickedEngine/wiInput.cpp index ecccf4b2b..c93930f1d 100644 --- a/WickedEngine/wiInput.cpp +++ b/WickedEngine/wiInput.cpp @@ -68,7 +68,7 @@ namespace wi::input } }; }; - std::map inputs; + std::map inputs; // Input -> down frames (-1 = released) wi::vector touches; struct Controller @@ -410,10 +410,14 @@ namespace wi::input { iter->second++; } - else + else if (iter->second == -1) { todelete = true; } + else + { + iter->second = -1; + } if (todelete) { @@ -652,6 +656,24 @@ namespace wi::input } return false; } + bool Release(BUTTON button, int playerindex) + { + Input input; + input.button = button; + input.playerIndex = playerindex; + auto iter = inputs.find(input); + if (iter == inputs.end()) + { + if (Down(button, playerindex)) + inputs.insert(std::make_pair(input, 0)); + return false; + } + if (iter->second == -1) + { + return true; + } + return false; + } bool Hold(BUTTON button, uint32_t frames, bool continuous, int playerIndex) { if (!Down(button, playerIndex)) @@ -666,7 +688,7 @@ namespace wi::input inputs.insert(std::make_pair(input, 0)); return false; } - else if ((!continuous && iter->second == frames) || (continuous && iter->second >= frames)) + else if ((!continuous && iter->second == (int)frames) || (continuous && iter->second >= (int)frames)) { return true; } diff --git a/WickedEngine/wiInput.h b/WickedEngine/wiInput.h index 02afbd80a..e99fb22c5 100644 --- a/WickedEngine/wiInput.h +++ b/WickedEngine/wiInput.h @@ -166,6 +166,8 @@ namespace wi::input bool Down(BUTTON button, int playerindex = 0); // check if a button is pressed once bool Press(BUTTON button, int playerindex = 0); + // check if a button has been just released + bool Release(BUTTON button, int playerindex = 0); // check if a button is held down bool Hold(BUTTON button, uint32_t frames = 30, bool continuous = false, int playerIndex = 0); // get pointer position (eg. mouse pointer) (.xy) + scroll delta (.z) + pressure (.w) diff --git a/WickedEngine/wiInput_BindLua.cpp b/WickedEngine/wiInput_BindLua.cpp index 8fe258eb5..bc8a6336b 100644 --- a/WickedEngine/wiInput_BindLua.cpp +++ b/WickedEngine/wiInput_BindLua.cpp @@ -7,6 +7,7 @@ namespace wi::lua Luna::FunctionType Input_BindLua::methods[] = { lunamethod(Input_BindLua, Down), lunamethod(Input_BindLua, Press), + lunamethod(Input_BindLua, Release), lunamethod(Input_BindLua, Hold), lunamethod(Input_BindLua, GetPointer), lunamethod(Input_BindLua, SetPointer), @@ -57,6 +58,24 @@ namespace wi::lua wi::lua::SError(L, "Press(int code, opt int playerindex = 0) not enough arguments!"); return 0; } + int Input_BindLua::Release(lua_State* L) + { + int argc = wi::lua::SGetArgCount(L); + if (argc > 0) + { + wi::input::BUTTON code = (wi::input::BUTTON)wi::lua::SGetInt(L, 1); + int playerindex = 0; + if (argc > 1) + { + playerindex = wi::lua::SGetInt(L, 2); + } + wi::lua::SSetBool(L, wi::input::Release(code, playerindex)); + return 1; + } + else + wi::lua::SError(L, "Release(int code, opt int playerindex = 0) not enough arguments!"); + return 0; + } int Input_BindLua::Hold(lua_State* L) { int argc = wi::lua::SGetArgCount(L); diff --git a/WickedEngine/wiInput_BindLua.h b/WickedEngine/wiInput_BindLua.h index abc305f0b..3db3efff6 100644 --- a/WickedEngine/wiInput_BindLua.h +++ b/WickedEngine/wiInput_BindLua.h @@ -17,6 +17,7 @@ namespace wi::lua int Down(lua_State* L); int Press(lua_State* L); + int Release(lua_State* L); int Hold(lua_State* L); int GetPointer(lua_State* L); int SetPointer(lua_State* L); diff --git a/WickedEngine/wiRenderPath3D.cpp b/WickedEngine/wiRenderPath3D.cpp index cd7cfff9e..d8ab5fedc 100644 --- a/WickedEngine/wiRenderPath3D.cpp +++ b/WickedEngine/wiRenderPath3D.cpp @@ -1159,7 +1159,7 @@ namespace wi RenderPassImage::DepthStencil( &depthBuffer_Reflection, RenderPassImage::LoadOp::LOAD, - RenderPassImage::StoreOp::DONTCARE, + RenderPassImage::StoreOp::STORE, ResourceState::SHADER_RESOURCE ), }; diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index bae51c508..378243138 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -4473,10 +4473,6 @@ namespace wi::scene { wi::audio::Stop(&sound.soundinstance); } - if (!sound.IsLooped()) - { - wi::audio::ExitLoop(&sound.soundinstance); - } wi::audio::SetVolume(sound.volume, &sound.soundinstance); } } diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index db674efd2..fa0556d9f 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -46,7 +46,7 @@ namespace wi::scene wi::ecs::ComponentManager& emitters = componentLibrary.Register("wi::scene::Scene::emitters"); wi::ecs::ComponentManager& hairs = componentLibrary.Register("wi::scene::Scene::hairs"); wi::ecs::ComponentManager& weathers = componentLibrary.Register("wi::scene::Scene::weathers", 4); // version = 4 - wi::ecs::ComponentManager& sounds = componentLibrary.Register("wi::scene::Scene::sounds"); + wi::ecs::ComponentManager& sounds = componentLibrary.Register("wi::scene::Scene::sounds", 1); // version = 1 wi::ecs::ComponentManager& videos = componentLibrary.Register("wi::scene::Scene::videos"); wi::ecs::ComponentManager& inverse_kinematics = componentLibrary.Register("wi::scene::Scene::inverse_kinematics"); wi::ecs::ComponentManager& springs = componentLibrary.Register("wi::scene::Scene::springs", 1); // version = 1 diff --git a/WickedEngine/wiScene_Components.cpp b/WickedEngine/wiScene_Components.cpp index f7fd128e2..c2e6fce37 100644 --- a/WickedEngine/wiScene_Components.cpp +++ b/WickedEngine/wiScene_Components.cpp @@ -1787,5 +1787,31 @@ namespace wi::scene _flags &= ~PLAYING; wi::audio::Stop(&soundinstance); } + void SoundComponent::SetLooped(bool value) + { + soundinstance.SetLooped(value); + if (value) + { + _flags |= LOOPED; + wi::audio::CreateSoundInstance(&soundResource.GetSound(), &soundinstance); + } + else + { + _flags &= ~LOOPED; + wi::audio::ExitLoop(&soundinstance); + } + } + void SoundComponent::SetDisable3D(bool value) + { + if (value) + { + _flags |= DISABLE_3D; + } + else + { + _flags &= ~DISABLE_3D; + } + wi::audio::CreateSoundInstance(&soundResource.GetSound(), &soundinstance); + } } diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index f03b979df..52ca8e294 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -1385,8 +1385,8 @@ namespace wi::scene void Play(); void Stop(); - inline void SetLooped(bool value = true) { if (value) { _flags |= LOOPED; } else { _flags &= ~LOOPED; } } - inline void SetDisable3D(bool value = true) { if (value) { _flags |= DISABLE_3D; } else { _flags &= ~DISABLE_3D; } } + void SetLooped(bool value = true); + void SetDisable3D(bool value = true); void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri); }; diff --git a/WickedEngine/wiScene_Serializers.cpp b/WickedEngine/wiScene_Serializers.cpp index 4e6d5dff6..8614c21d9 100644 --- a/WickedEngine/wiScene_Serializers.cpp +++ b/WickedEngine/wiScene_Serializers.cpp @@ -1660,11 +1660,20 @@ namespace wi::scene archive >> volume; archive >> (uint32_t&)soundinstance.type; + if (seri.GetVersion() >= 1) + { + archive >> soundinstance.begin; + archive >> soundinstance.length; + archive >> soundinstance.loop_begin; + archive >> soundinstance.loop_length; + } + wi::jobsystem::Execute(seri.ctx, [&](wi::jobsystem::JobArgs args) { if (!filename.empty()) { filename = dir + filename; soundResource = wi::resourcemanager::Load(filename, wi::resourcemanager::Flags::IMPORT_RETAIN_FILEDATA); + soundinstance.SetLooped(IsLooped()); wi::audio::CreateSoundInstance(&soundResource.GetSound(), &soundinstance); } }); @@ -1677,6 +1686,14 @@ namespace wi::scene archive << filename; archive << volume; archive << soundinstance.type; + + if (seri.GetVersion() >= 1) + { + archive << soundinstance.begin; + archive << soundinstance.length; + archive << soundinstance.loop_begin; + archive << soundinstance.loop_length; + } } } void VideoComponent::Serialize(wi::Archive& archive, EntitySerializer& seri) diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index b9c44b9b4..64eb44149 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 71; // minor bug fixes, alterations, refactors, updates - const int revision = 314; + const int revision = 315; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);