Commit Graph

8187 Commits

Author SHA1 Message Date
SpomJ
7e65a87ba8 Fix unrestricted splash screen geometry (#7588) 2024-11-20 14:08:27 -05:00
Rossmaxx
0d7749d944 Fix the MSVC CI fail happening due to outdated vcpkg (#7589)
* switch to version 1 for msvc-dev-cmd github action

* bump msvc build year

* try refreshing vcpkg cache msvc

* Revert "try refreshing vcpkg cache msvc"

This reverts commit e8814f8cbd.

* try updating vcpkg manually

* Revert "bump msvc build year"

This reverts commit a95c75ee95.

* messmerd's review comments

* revert the version bump for msvc-dev-cmd

* Fix `cd` command

---------

Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com>
2024-11-20 13:33:58 -05:00
Kapandaria
ada836c989 Fix crash on Xpressive when using integrate function (#7499)
* Fixed a bug in the integrate function, that was caused by warning fixes session.

* Xpressive - fixed code style issues.
2024-11-08 16:15:34 -05:00
Dalton Messmer
e36463ce77 Update macOS CI (#7572)
* Use macOS 13

See: https://github.com/actions/runner-images/issues/10721

* Upgrade to XCode 15.2

XCode 15.2 is the default on macOS 13

* Fix unqualified call to std::move warning

* Fix sprintf deprecated warnings

* Upgrade macOS 14 ARM64 builds to XCode 15.4

See: https://github.com/actions/runner-images/issues/10703

* Fix unused lambda capture warnings in Fader.cpp

* Fix unused variable warnings

* Fix formatting warning

Cannot format `const void*` as a string

* Force lambda conversion to function pointer
2024-11-06 17:46:12 -05:00
saker
07baf9e27a Tidy up MixerChannelView (#7527) 2024-11-03 02:13:55 -05:00
Rossmaxx
9912fd88e3 Add member variable for base sample rate and inline sample rate getter functions (#7552)
Co-authored-by: saker <sakertooth@gmail.com>
2024-10-30 19:55:11 -04:00
cyberrumor
b5de1d50e1 Fix PeakController attack/decay, use linear interpolation between samples (#7566)
Historically, the PeakController has had issues like attack/decay knobs
acting like on/off switches, and audio artifacts like buzzing or
clicking. This patch aims to address those issues.

The PeakController previously used lerp (linear interpolation) when
looping through the sample buffer, which was in updateValueBuffer. This
lerp utilized attack/decay values from control knobs. This is not the
correct place to utilize attack/decay because the only temporal data
available to the function is the frame and sample size. Therefore the
coefficient should simply be the sample rate instead.

Between each sample, processImpl would set m_lastSample to the RMS
without any sort of lerp. This resulted in m_lastSample producing
stair-like patterns over time, rather than a smooth line.

For context, m_lastSample is used to set the value of whatever is
connected to the PeakController. The basic lerp formula is:

m_lastSample = m_lastSample + ((1 - attack) * (RMS - m_lastSample))

This is useful because an attack of 0 sets m_lastSample to RMS, whereas
an attack of 1 would set m_lastSample to m_lastSample. This means our
attack/decay knobs can be used on a range from "snap to the next value
immediately" to "never stray from the last value".

* Remove attack/decay from PeakController frame lerp.
* Set frame lerp coefficient to 100.0 / sample_rate to fix buzzing.
* Add lerp between samples for PeakController to fix stairstep bug.
* The newly added lerp utilizes (1 - attack or decay) as the
  coefficient, which means the knobs actually do something now.
2024-10-28 15:01:08 -04:00
saker
1f37c9ba7c Inline TimePos and TimeSig functions to improve performance (#7549)
* Inline TimeSig functions

* Inline TimePos functions
2024-10-26 12:41:46 -04:00
Dalton Messmer
e6776bcfe5 Remove usage of QTextCodec in Hydrogen Import plugin (#7562)
* Remove QTextCodec

QTextCodec was removed from Qt6 and is only available through the
Qt5Compat module.

QTextCodec was only used by the HydrogenImport plugin when importing old
Hydrogen files that were saved using TinyXML before it supported UTF-8.
HydrogenImport would use QTextCodec to try to get the current encoding
from the locale, and then use that as a best guess for interpreting the
XML data in the unspecified encoding it was saved in. None of this was
ever reliable, since the encoding of the computer that saved the
Hydrogen file might not be the same as the computer running LMMS and
importing that file.

There is no good solution here, so I decided to simply assume the old
Hydrogen files are UTF-8 encoded. The worst that can happen is someone's
ancient Hydrogen files containing non-ASCII text of some random encoding
becomes mojibake'd after importing into LMMS, which is something that
already could have happened.

* Clean up a little
2024-10-23 13:17:14 -04:00
Lost Robot
b8b1dae407 Optimize dBFS/amplitude conversion functions (#7535)
* Optimize dBFS <-> amplitude functions
2024-10-15 17:59:47 +05:30
Johannes Lorenz
97b61bbd9a Make PluginView::isResizable a virtual (#7541)
Remove the member `PluginView::m_isResizable` and it's associated method `setResizable`. Turn `isResizable` into a virtual method.

The reasoning is that whether or not an effect can be resized depends on its implementation. Therefore does not make sense to have a method like `setResizable`. If the underlying implementation does not support resizing then it would not make sense to call `setResizable(true)`. So `isResizable` now describes the underlying ability of a plugin to resize. It's then up to the clients of that method to decide how to treat the result of `isResizable`, i.e. if they want to make use of the ability to resize or not.
2024-10-12 10:39:42 +02:00
Michael Gregorius
fb5516cfdc Track operations widget with layout (#7537)
Put the elements of the `TrackOperationsWidget` into layouts. These are:
* The grip that can be used to move tracks
* The gear icon that opens the operations menu
* The mute button
* The solo button

The grip that can be used to move tracks around is extracted into its own class called `TrackGrip`. This has several advantages:
* It can be put into a layout.
* It can render itself at arbitrary sizes by simply repeating its pattern pixmap.
* It can be used in a much more object-oriented way because it emits signals when it is grabbed and released.
* It is responsible for locally updating its cursor state.

The default cursor of the grip now is an open hand which indicates to the users that it can be grabbed. While being grabbed the cursor now is a closed hand.

## Technical details
The class `TrackOperationsWidget` now holds an instance of `TrackGrip` and provides a getter to retrieve it. This getter is used by `TrackView` to connect to the two new signals `grabbed` and `released`. The method `TrackOperationsWidget::paintEvent` now only paints the background as it does not need to paint the grip anymore.

The `TrackView` now handles the grabbing and release of the grip in `TrackView::onTrackGripGrabbed` and `TrackView::onTrackGripReleased`. Because the events and cursor states are now handled by `TrackGrip` this code could be removed from `TrackView::mousePressEvent`.

There was a comment in `TrackView` which indicated that the `TrackOperationsWidget` had to be updated when the track is moved and released because it would hide some elements during the move. The comment and the corresponding code was removed because the operations widget does not hide its elements during moves (this was already the state before the changes made by this commit).

Adjust the style sheets of the classic and default themes with regards to the `QPushButton` that's used to show the gear menu in the `TrackOperationsWidget`. The `>` has been removed because the `QPushButton` is not a direct decendent of the `TrackOperationsWidget` anymore.

### Wrapping of `PixmapButton` in `QWidget`
The PixmapButtons that are used in `TrackOperationsWidget` current have to be wrapped into a `QWidget`. This is necessary due to some strange effect where the PixmapButtons are resized to a size that's larger than their minimum/fixed size when the method `show` is called in `TrackContainerView::realignTracks`. Specifically, with the default theme the buttons are resized from their minimum size of (16, 14) to (26, 26). This then makes them behave not as expected in layouts.

The resizing is not done for QWidgets. Therefore we wrap the PixmapButton in a QWidget which is set to a fixed size that will be able to show the active and inactive pixmap. We can then use the QWidget in layouts without any disturbances.

The resizing only seems to affect the track view hierarchy and is triggered by Qt's internal mechanisms. For example the buttons in the mixer view do not seem to be affected.

If you want to debug this simply override "PixmapButton::resizeEvent" and trigger a break point in there, e.g. whenever the new size is not (16, 14).

### More layout-friendly PixmapButton

Make the `PixmapButton` more friendly for layouts by implementing `minimumSizeHint`. It returns a size that accommodate to show the active and the inactive pixmap.

Also make `sizeHint` return the minimum size hint. The previous implementation would have made layouts jump when the pixmap is toggled with pixmaps of different sizes.
2024-10-12 10:02:56 +02:00
Michael Gregorius
378ff8bab0 Fix the maximization of sub windows (#7530)
## Fix rendering of maximized sub windows

### Adjustments in paintEvent
In `SubWindow::paintEvent` don't paint anything if the sub window is
maximized . Otherwise some gradients are visible behind the maximized
child content.

### Adjustments in adjustTitleBar
In `SubWindow::adjustTitleBar` hide the title label and the buttons if the
sub window is maximized. Always show the title and close button if not
maximized. This is needed to reset the state correctly after
maximization.

Remove some calls to `isMaximized` where we already know that the sub
window is not maximized, i.e. where these calls would always return
`false`.

One adjustment would have resulted in a call to `setHidden(false)`. This
was changed to `setVisible(true)` to get rid of the double negation.

The other `false` would have gotten in an or statement and thus could be
removed completely.

### Add method addTitleButton
Add the helper method `SubWindow::addTitleButton` to reduce code
repetition in the constructor.

### Other changes
Remove a dependency on the `MdiArea` when checking if the sub window is
the active one. Query its own window state to find out if it is active.

When calling `setWindowFlags` in the constructor only adjust the existing
flags with the changes that we actually want to do. It was ensured that
all other flags that have been set before still apply with this change.
2024-10-10 10:36:25 +02:00
Steffen Baranowsky
066f6b5e95 Align the rename line edit for tracks (#7414)
Align the rename line edit for tracks.

Make sure that the rename line edit of the `TrackLabelButton` has the
same font size as the widget itself. Because the font size is defined
via style sheets the font size of the line edit has to be set when the
actual renaming starts and not in the constructor. The reason is that
style sheets are set after the constructor has run.

Rename the local variable `txt` to the more speaking name `trackName`.

Ensure that the line edit is moved to the correct place for different
icon sizes by taking the icon size into account. To make this work this
also has to be done in the `rename` method.

## Other changes

Streamline the default style sheet of `TrackLabelButton` by removing
repeated properties that are inherited from the "main" style sheet, i.e.
that are already part of `lmms--gui--TrackLabelButton`.

Interestingly, the `background-color` property had to be repeated for
`lmms--gui--TrackLabelButton:hover`.

---------

Co-authored-by: Michael Gregorius <michael.gregorius.git@arcor.de>
2024-10-07 13:25:11 +02:00
Rossmaxx
79eac411a0 Removed dead code using #if 0 (#7521)
Removed code that's has been deactivated using `#if 0`.
2024-10-07 13:21:18 +02:00
firewall1110
639e122efe Fix empty editor windows (#7515)
Fix the problem with empty windows as described in issue #7412.

The `refocus` method in `MainWindow` is made public so that it can be called from `Editor::closeEvent`. It has also been refactored for better readability.

---------

Co-authored-by: Michael Gregorius <michael.gregorius.git@arcor.de>
Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com>
2024-10-07 13:15:07 +02:00
regulus79
7dbc80926d Adding proportional scrolling (#7476)
Add proportional scrolling to the song editor, piano roll and automation editor. Proportional scrolling means that if for example a certain measure is on the right side of the song editor then it will take a certain number of mouse wheel moves to get it to the left side of the editor. It is the same number of wheel moves regardless of the zoom level.
2024-10-06 21:27:39 +02:00
Lisa Magdalena Riedler
0363ee6d16 fix various AudioFileProcessor bugs (#7533)
* fix out-of-bounds crash in AudioFileProcessor

by correctly setting m_from and m_to without them interfering with each other

* fixed flattened wave caused by inaccurate math

see PR for before/after

* simply stop drawing AFP waveform when there's no more data

this fixes the single point at the end of waveforms that sometimes shows up

* fixed seemingly insignificant type confusion (?)

execution seemed fine but my debugger started freaking out,
and if gdb is telling me I got a negative-sized vector,
I'd rather fix this issue than speculate "it's probably fine"

* fixed data offset for AFP waveform vis

the data itself isn't reversed, so we have to account for that
2024-10-06 11:26:57 +02:00
LMMS Service
e0ae8a1cec locale: Update translations 2024-10-02 10:57:13 -06:00
liushuyu
a83130f8c9 .tx/config: migrate the configuration to v2 format 2024-10-02 10:57:13 -06:00
Dalton Messmer
121d608c3a Reintroduce fast math functions (#7495)
* Add fast fma functions

* Use fast fma functions

* Add fast pow function

* Use fast pow function

* Fix build

* Remove fastFma

* Avoid UB in fastPow

On GCC with -O1 or -O2 optimizations, this new implementation generates
identical assembly to the old union-based implementation
2024-10-01 14:35:15 -04:00
saker
860749a8a1 Reformat MixerChannelView classes (#7431) 2024-09-30 19:32:21 -04:00
Rossmaxx
729593c022 Fix hardcoded fonts scaling issues (#7493)
* changed font sizes to better values

* rename gui_templates.h to FontHelper.h

* replace hardcoded values with constants

* make knob labels use small font

* code review from michael

* more consolidation

* Fix text problem in Vectorscope

Fix a problem with cutoff text in Vectorscope. During the constructor
call of `LedCheckBox` the method `LedCheckBox::onTextUpdated` is
triggered which sets a fixed size that fits the pixmap and the text.
After instantiating the two instances in `VecControlsDialog` the
constructor then set a minimum size which overrode the fixed size that
was previously set. This then led to text that was cutoff.

---------

Co-authored-by: Michael Gregorius <michael.gregorius.git@arcor.de>
2024-09-28 13:18:02 +05:30
saker
6a7b23b278 Partially revert #7453 (#7519) 2024-09-26 08:56:34 -04:00
Dalton Messmer
18252088ba Refactor Effect processing (#7484)
* Move common effect processing code to wrapper method

- Introduce `processImpl` and `sleepImpl` methods, and adapt each effect
plugin to use them
- Use double for RMS out sum in Compressor and LOMM
- Run `checkGate` for GranularPitchShifterEffect
- Minor changes to LadspaEffect
- Remove dynamic allocations and VLAs from VstEffect's process method
- Some minor style/formatting fixes

* Fix VstEffect regression

* GranularPitchShifterEffect should not call `checkGate`

* Apply suggestions from code review

Co-authored-by: saker <sakertooth@gmail.com>

* Follow naming convention for local variables

* Add `MAXIMUM_BUFFER_SIZE` and use it in VstEffect

* Revert "GranularPitchShifterEffect should not call `checkGate`"

This reverts commit 67526f0ffe.

* VstEffect: Simplify setting "Don't Run" state

* Rename `sleepImpl` to `processBypassedImpl`

* Use `MAXIMUM_BUFFER_SIZE` in SetupDialog

* Pass `outSum` as out parameter; Fix LadspaEffect mutex

* Move outSum calculations to wrapper method

* Fix Linux build

* Oops

* Apply suggestions from code review

Co-authored-by: Johannes Lorenz <1042576+JohannesLorenz@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: saker <sakertooth@gmail.com>

---------

Co-authored-by: saker <sakertooth@gmail.com>
Co-authored-by: Johannes Lorenz <1042576+JohannesLorenz@users.noreply.github.com>
2024-09-20 20:00:36 -04:00
saker
1d7ed16dc9 Make the send button and receive arrow occupy the same space in mixer channels (#7503) 2024-09-19 12:53:40 -04:00
saker
c952d56591 Restore some whitespace to the mixer channel layout (#7507) 2024-09-19 12:00:16 -04:00
saker
01294192c8 Fix Lb302 silence (#7504)
This problem seem to arise due to casting _n->framesLeft() and _n->offset() from an unsigned type (size_t) to a signed type (int). The fix is to use size_t as the type for std::max across the board.
2024-09-18 11:25:47 -04:00
saker
4803bbb73a Shrink mixer channel strip (#7502)
Remove all content margins and spacing between child widgets for each mixer channel strip.
2024-09-18 04:45:46 -04:00
DanielKauss
7d35d4225e SlicerT UI update (#7453)
* Update SlicerT UI

* Style review

Co-authored-by: Rossmaxx <74815851+Rossmaxx@users.noreply.github.com>

* Style fixes

---------

Co-authored-by: Rossmaxx <74815851+Rossmaxx@users.noreply.github.com>
2024-09-17 11:35:01 +05:30
Lost Robot
588aab3389 Replace Compressor infinite ratio icons (#7501) 2024-09-15 21:40:05 +05:30
regulus79
48314959b8 Fix sample clip position when reversing (#7446) 2024-09-13 18:54:00 -04:00
saker
d703f39153 Process metronome every MIDI tick (#7483) 2024-09-04 12:58:36 -04:00
Grzegorz Pruchniakowski
b81f806d63 Fix: unnecessary space in Update EqControlsDialog.cpp (#7485)
* Fix: unnecessary space in Update EqControlsDialog.cpp

Fix: unnecessary space in Update EqControlsDialog.cpp

Greetings,
Gootector

* Style fix from Ross

---------

Co-authored-by: Rossmaxx <74815851+Rossmaxx@users.noreply.github.com>
2024-09-03 18:00:28 +05:30
Grzegorz Pruchniakowski
9a76d31732 Fix typo in DataFile.cpp (#7478) 2024-09-02 10:44:44 -04:00
Rossmaxx
35f350eeff Remove Noise class from flanger (#7473) 2024-08-28 15:46:48 -04:00
Rossmaxx
a992019626 Cleanup lmms_math.h (#7382)
* simplified fraction and absfraction functions

* removed unused fastSqrt() and fastPow()  
functions

* unused absMin() and absMax()

* move roundAt to math header

* Code review from saker

Co-authored-by: saker <sakertooth@gmail.com>

* use std::trunc()

* fixup after fixing merge conflicts

* remove unused fastFma and fastFmal functions.

* remove lmms_basics include, not needed

* use signedPowf from lmms_math in NES

* removed fastRand function, unused

* remove unused sinc function

* cleanup signedPowf

* code review

* further simplify random number math

* removed static from lmms_math file

---------

Co-authored-by: saker <sakertooth@gmail.com>
2024-08-28 12:48:56 +05:30
saker
ff8c47062f Continue processing Song even when no tracks are found (#7458) 2024-08-20 14:32:46 -04:00
Michael Gregorius
88ee83bb4a Do not save MIDI connections in presets (#7445)
Ensure that no MIDI information (connected inputs, outputs, etc.) is
stored in presets. This main fix can be found in
`InstrumentTrack::saveTrackSpecificSettings` where the state of the
MIDI ports are now only saved if we are not in preset mode.

The remaining changes are concered with a refactoring of the code
that's related to saving and loading presets.

The refactoring mainly revolves around the removal of the member
`m_simpleSerializingMode` and the method `setSimpleSerializing` in
`Track`.

This is accomplished by introducing two new methods `saveTrack` and
`loadTrack`. These methods have a similar interface to `saveSettings`
and `loadSettings` but they additionally contain a boolean which
indicates if a preset is saved/loaded or a whole track. Both new
methods contain the previous code of `saveSettings` and `loadSettings`.
The latter two now only delegate to the new methods assuming that the
full track is to be stored/loaded if called via the overridden methods
`saveSettings` and `loadSettings`.

The methods `savePreset` and `loadPreset` are added as well. They call
`saveTrack` and `loadTrack` with the preset boolean set to `true`.
These methods are now used by all places in the code where presets are
saved or loaded which makes the code more readable. Clients also do not
need to know any implementation details of `Track`, e.g. like having to
call `setSimpleSerializing`.

Adjust `saveTrackSpecificSettings` so that it also passes information
of whether a preset or a whole track is stored. This leads to changes
in the interfaces of `AutomationTrack`, `InstrumentTrack`,
`PatternTrack` and `SampleTrack`. Only the implementation of
`InstrumentTrack` uses the new information though.
2024-08-20 19:50:39 +02:00
szeli1
5e697f01c8 Fix zooming and sliding of the waveform view in AudioFileProcessor (#7377) 2024-08-19 13:20:19 -04:00
Alex
58ce9b476a Fix track handles dissapearing (#6338) 2024-08-16 22:20:39 +05:30
szeli1
bda1a9c37e Add input dialog to the mixer channel LCD spin box (#7399)
Co-authored-by: saker <sakertooth@gmail.com>
2024-08-11 11:14:43 -04:00
Michael Gregorius
d8e4d8c115 Remove support for SDL1 (#7443)
Remove the fallback code in `CMakeLists.txt`. Keep the message that's shown when SDL is wanted but not found. Remove the specific `LMMS_HAVE_SDL2` define.

Just print "OK" if SDL is found.

Remove several ifdefs which check for SDL2 or SDL1. Remove all code related to SDL1.
2024-08-11 12:20:02 +02:00
regulus79
0e96c267cd Fix bug with continuous autoscrolling when smooth scrolling is enabled (#7433) 2024-08-10 22:39:55 -04:00
Michael Gregorius
74c73e5848 SDL driver's input and output device configuration via combo box (#7421)
* Enable configuration of input device for SDL

Up to now the SDL audio driver attempted to use the default recording
device. This might not be what users want or expect, especially since the
actually used device is not visible anywhere. So if recording does not
work for the users they have no way to find out what's wrong.

Extend the settings screen of the SDL driver with a combo box that allows
to select the input device to be used. Store the selected device name in
a new attribute called "inputdevice" in the "audiosdl" section of the
configuration file.

Use the information from the configuration when attempting to inialize
the input device. Fall back to the default device if that does not work.

(cherry picked from commit 33139b9f4c)

* Provide a setting for system default input

Provide the setting "[System Default]" which instructs the SDL driver to
use the default device of the system as the input device. In the
configuration file this option is represented as an empty string. This
should play well with the current existing configuration of the users.

(cherry picked from commit 29c43c2bb6)

* Configuration of output device for SDL

Let users configure the output device that's used by the SDL driver.
Code-wise the implementation is very similar to the input device
configuration.

Use a `QComboBox` instead of a `QLineEdit` for `m_device` and rename it
to `m_playbackDeviceComboBox`.

Rename `s_defaultInputDevice` to `s_systemDefaultDevice` because it is
used in the context of playback and input devices.

(cherry picked from commit 1ab45e4994)

* Ensure label visibility

Make sure that labels are always shown by setting the row wrap policy of
the form layout to wrap long rows.

(cherry picked from commit a123d0e3cb)

* Rename "Device"

Rename "Device" to "Playback device" to make clear what the setting
refers to.

(cherry picked from commit 1f0cda4983)

* Remove repeated strings

Introduce const expressions to get rid of repeated strings with a risk
of typos.

(cherry picked from commit f9ea9705b8)

* Apply some more changes

Apply some more changes that have been made to `AudioSdl` in the
recording branch.

* Conditional ternary operator

Also use a conditional ternary operator for the input device setup.

* Methods for population of combo boxes

Move the population of the input and playback device combo boxes into
the methods `populatePlaybackDeviceComboBox` and
`populateInputDeviceComboBox`.

* Sort devices in combo box

Sort the devices names alphabetically in the input and playback combo
boxes. The default devices is always shown as the first entry.

* Code review fixes

Use `AudioDeviceSetupWidget` instead of `QObject` to translate "[System
Default]".

Fix copy/paste error in comment.

* Simplify some constexpr statements
2024-08-10 22:33:52 +02:00
Johannes Lorenz
44a8b038f5 Fix #5851: Implement EffectRackView::sizeHint() (#7428)
* Fix #5851: Implement `EffectRackView::sizeHint()`

This fixes `EffectRackView` to have a permanent size hint instead of
resizing the widget once in `InstrumentTrackWindow`. The size hint tells
the `InstrumentTrackWindow` to not increase with a growing number of
effects in the `EffectRackView`.
2024-08-10 09:00:06 +05:30
saker
632966caee Do not put the main thread in realtime or high priority (#7436) 2024-08-07 13:12:37 -04:00
Rossmaxx
6c7fecd8d7 Fix build regression from #7380 (#7437) 2024-08-06 23:23:17 -04:00
Rossmaxx
828cefb4ea Remove typeInfo struct from lmms_basics.h (#7380)
* remove typeInfo struct from lmms_basics.h

* Code review

Co-authored-by: saker <sakertooth@gmail.com>

* converted epsilon to a constant

* renamed to approximatelyEqual and moved to top

---------

Co-authored-by: saker <sakertooth@gmail.com>
2024-08-07 07:33:10 +05:30
szeli1
c16616cca4 Fix duplication of solo state when cloning tracks (#7391) 2024-08-05 07:16:03 -04:00