Commit Graph

18 Commits

Author SHA1 Message Date
ferreum 096d35dac7 af_scaletempo2: prioritize louder channels for similarity measure
Playback with many audio channels could be distorted when using
scaletempo2. This was most noticeable when there were a lot of quiet
channels and few louder channels.

Fix this by increasing the weight of louder channels in relation to
quieter channels. Each channel's target block energy is factored into
the usual similarity measure.

This should have little effect on very correlated channels (such as most
stereo media), where the factors are very similar for all channels.

See-Also: #8705
See-Also: #13737
2024-04-12 17:40:00 +00:00
nanahi 7ab1080749 af_scaletempo2: fix false reporting of frame availability
With certain speed settings, the following can happen at the start of
the playback:

- can_perform_wsola returns false, so no frames are written
- mp_scaletempo2_frames_available returns true when
  p->input_buffer_final_frames is 0 and target_block_index < 0

This results in infinite loop and completely stalls audio filter
processing and playback. Fix this by only checking this condition
after the final frame is set.

Fixes: 8080d00d7f
2024-03-28 16:16:43 +01:00
ferreum 95157bb0a5 af_scaletempo2: fix missing variable init, remove redundant init 2023-09-20 14:36:23 +02:00
ferreum 8080d00d7f af_scaletempo2: fix processing of final packet
After the final input packet, the filter padded with silence to allow
one more iteration. That was not enough to process the final frames.

Continue padding the end of `input_buffer` with silence until the final
frames have been processed.

Implementation: Instead of padding when adding final samples, pad before
running WSOLA iteration. Count number of added silent frames and
remaining input frames for time keeping.
2023-09-20 14:36:23 +02:00
ferreum cf8b7ff0d6 af_scaletempo2: calculate latency by center of search block
This changes the emitted pts values from the start of the search block
to the center of the search block. Change initial `output_time`
accordingly. Initial `search_block_index` is irrelevant, because it's
overwritten before the first iteration.

Using the `output_time` removes the rounding of `search_block_index`,
which also fixes the <20 microsecond gaps in timestamps between output
packets.

Rationale:

The variance in audio position was in the range `0..search-interval`.

With this change, the range is

    (- search-interval / 2)..(search-interval / 2)`

which ensures lower maximum offset.
2023-09-20 14:36:23 +02:00
ferreum c0728249a1 af_scaletempo2: restore exact audio sync on return to 1x speed
Target block can be anywhere in the previous search-block, varying by
`search-interval` while the filter is active. This resulted in constant
audio offset when returning to 1x playback speed.

- Move the search block to the target block to sync up exactly.
- Drop old frames to minimize input_buffer usage.
2023-09-20 14:36:23 +02:00
ferreum f52cf90fed af_scaletempo2: fix speed change latency and pts spikes
The internal time update function involved multiple problems:

- Time was updated after WSOLA iteration. The means speed was updated
  one iteration later than it could be.
- The update functions caused spikes of too many or too few samples
  advanced, leading to audio glitches on speed changes.
- The inconsistent updates made it very difficult to produce gapless
  audio packets.
- The `output_time` update function involved complicated feedback:
  `search_block_index` influenced how many frames from `input_buffer`
  are retained, which influenced how much `output_time` is changed,
  which influenced `search_block_index`.

With these changes:

- Time is updated before WSOLA iterations. Speed changes are effective
  instantly.
- There are no spikes in playback speed during speed changes.
- No significant gaps are introduced in output packets.
- The time update function becomes (function calls omitted for brevity)

    output_time += ola_hop_size * playback_rate

Functions received a `playback_rate` parameter to check how many samples
are needed before iteration. Internal state is only updated when the
iteration is actually run, so the speed is allowed to change until
enough data is received.
2023-09-20 14:36:23 +02:00
ferreum 33d6d0f311 af_scaletempo2: fix audio artifact on initial WSOLA iteration
The first WSOLA iteration overlapped audio with whatever was in the
`wsola_output` buffer. This was either silence (if not run before), or
old frames (if switching to 1x and back to a different speed).

Track the state of the output buffer and memcpy the whole window for the
first iteration instead.
2023-09-20 14:36:23 +02:00
ferreum c3bceb3243 af_scaletempo2: fix audio offset when playing back at 1x speed
`read_input_buffer` needs to respect the `target_block_index`, otherwise
the audio resumes at the wrong position.
2023-09-20 14:36:23 +02:00
ferreum de09ec9ea4 af_scaletempo2: fix inconsistent search block position after init
`output_time` is used to set the center of the search block. Init of
both `search_block_index` and `output_time` with 0 caused inconsistent
search block movement for the first iterations.

Initialize with `search_block_center_offset` for consistency with initial
`search_block_index`.
2023-09-20 14:36:23 +02:00
ferreum 87cc7ed955 af_scaletempo2: move latency calculation to internal function 2023-09-20 14:36:23 +02:00
ferreum 0d64f795c7 af_scaletempo2: fix missing dereference when processing final packet
Missing dereference was not noticed because assigning 0 to pointer is
allowed.
2023-09-20 14:36:23 +02:00
Peter DeLong f46bbde5e6 af_scaletempo2: fix crash when the number of channels increases
When af_scaletempo2.c:process() detects a format change, it goes back
through mp_scaletempo2_init() to reinitialize everything.  However,
mp_scaletempo2.input_buffer is not necessarily reallocated due to a
check in af_scaletempo2_internals.c:resize_input_buffer().  This is a
problem if the number of audio channels increases, since without
reallocating, the buffer for the new channel(s) will at best point to
NULL, and at worst uninitialized memory.

Since resize_input_buffer() is only called from two places, pull size
check out into mp_scaletempo2_fill_input_buffer().  This allows each
caller to decide whether they want to resize or not.  We could be
smarter about when to reallocate, but that would add a lot of machinery
for a case I don't expect to be hit often in practice.
2022-09-23 18:15:00 +02:00
Guido Cella fe9e074752 various: remove trailing whitespace 2022-05-14 14:51:34 +00:00
Niklas Haas ec0006bfa1 af_scaletempo2: use gcc vectors to speed up inner loop
This brings my scaletempo2 benchmark down from ~22s to ~7s on my machine
(-march=native), and down to ~11s with a generic compile.

Guarded behind an appropriate #ifdef to avoid being ableist against
people who have the clinical need to run obscure platforms.

Closes #8848
2021-05-26 17:35:55 +02:00
Dorian Rudolph 2e45a3d336 af_scaletempo2: fix crash for speed >= 16
The input buffer size was fixed, but the required size depends on the
speed. Now the buffer will be resized dynamically.

Fixes #8081
2021-02-15 00:07:27 +02:00
wm4 1fe6def066 af_scaletempo2: M_PI is always defined
I forgot why/how (C99?), but other code also uses it.
2020-07-27 00:59:37 +02:00
Dorian Rudolph 785a2b1261 audio: add scaletempo2 filter based on chromium
scaletempo2 is a new audio filter for playing back
audio at modified speed and is based on chromium
commit 51ed77e3f37a9a9b80d6d0a8259e84a8ca635259.
It sounds subjectively better than the existing
implementions scaletempo and rubberband.
2020-07-27 00:57:22 +02:00