otsaloma / gaupol

Editor for text-based subtitle files
https://otsaloma.io/gaupol/
GNU General Public License v3.0
249 stars 35 forks source link

Audio waveform widget #49

Open dumblob opened 7 years ago

dumblob commented 7 years ago

After using Gaupol for some time I must say it's a great tool, but I lack one thing. It's pretty difficult to make the timing right if there is just the audio feedback and the speed the reaction of your fingers. I think way better would be to have a simple audio frequency visualization with the possibility to select range with mouse. One could then add a new subtitle record, write some text and then select beginning with mouse left click and select end with mouse right click - both on a stripe visualizing the audio frequency.

The selection on the stripe shall be synchronized with selected subtitle record, so that one can scroll in the list of subtitle records, click on one and the visualization of audio frequency will immediately select the corresponding range.

What do you think?

otsaloma commented 7 years ago

I agree, it would be useful. An audio waveform display was on the TODO-list for a long time, until I concluded that it sounds like a lot of work and I don't have the time to do it in the foreseeable future. So, I'm unlikely to do it, but I would accept contributions and provide any help needed.

cirosantilli commented 3 years ago

I think https://github.com/Aegisub/Aegisub is the way to go nowadays.

milahu commented 2 years ago

I think https://github.com/Aegisub/Aegisub is the way to go nowadays.

active fork https://github.com/TypesettingTools/Aegisub

the beauty of a python tool: no need to compile, so its easier to hack

mvaranda commented 1 year ago

I felt the same. I am adding a wave widget in my clone and will create a PR once I have something featured and clean.

mvaranda commented 1 year ago

WIP: https://rumble.com/v2jzbv2-april-23-2023.html

otsaloma commented 1 year ago

Looks good so far.

I'm here and on Gitter, whichever you prefer, if you have questions. (Gitter seems to have gone full Matrix, I'm not up to speed on that, might not have notifications set up properly, but maybe I'll figure it out.)

mvaranda commented 1 year ago

Thanks, I would prefer to avoid creating accounts in another forum sites (Gitter). We can communicate here, Linkedin or Signal. Here may be better as others can also learn. As I explained in my video I did not understand how your Signal/emit implementation works. I tried creating methods starting with "on_". Connect requires self/self/signal-name or self/""/signal-name". I could not make the dispatcher happy. Not sure which attribute it is looking for. the self/self/signal-name" seems to have no point as I want to send signals cross objects (not to itself).

Creating a signal in my Observable derived class seem to not become global as emitting it from other objects do nothing (handler never called). The code under "mv" has the class "SignalPoster" with a hack as I was not able to emit signal without getting reference from the object "owning" the signal. Giving parent access to children is bad architecture and I want to remove that hack.

I also tried to add emit from "page" instance to my Waveviewer (or maybe SignalPoster) to get notification when the subtitles object has changed. I tried different things and I was not able to figure out the way to go.

My suggestion: when you have a chance please write down a few lines showing how two instances from different classes can emit signals to/from each other. That would be helpful.

BTW... this project is very well implemented. I believe that by just adding a few shortcuts combined with mouse ( dragging) would increase the productivity for the users. For example, in Blender you can click/hold/drag any numeric field to increase/decrease values. That would speed-up changing start/end time. "Shift" key decreases the sensibility while dragging when precision is desired. This is just one example; typing to adjust time is not productive.

Thanks a lot, Marcelo

otsaloma commented 1 year ago

Does this help?

#!/usr/bin/env python3

import aeidon

class Child(aeidon.Observable):

    signals = ("stuff-done",)

    def do_stuff(self):
        # Do something here,
        # once done emit:
        self.emit("stuff-done")

class Parent:

    def __init__(self):
        self.child = Child()
        self.child.connect("stuff-done", self._on_child_stuff_done)

    def _on_child_stuff_done(self, child):
        print("Callback: _on_child_stuff_done!")

parent = Parent()
parent.child.do_stuff()

Note that many parts use the helper function aeidon.util.connect as it allows shorter code, but as a tradeoff, it's probably just too much magic under the hood and unclear as a result. In here it'd be

aeidon.util.connect(self, "child", "stuff-done")

but it's probably better to avoid that helper.

otsaloma commented 1 year ago

Also note that GTK widgets are GObjects and they have the signal mechanism from GObject. GObject and Observable and different implementations of the same thing and you can't mix them in a single class. Using custom signals in a GTK class is complicated, badly documented and at worst liable to break with new GTK/GObject versions. I'd recommend avoiding it. For an example of that, see CellTextView in https://github.com/otsaloma/gaupol/blob/master/gaupol/renderers/multiline.py#L34

mvaranda commented 1 year ago

That helps. I fixed signal for SignalPoster class. But still not clear how classes without relationship (parenthood) can communicate. Please check the other (ugly) code under: https://github.com/Varanda-Labs/gaupol/blob/mv/gaupol/page.py line 147

Forces exposing the singleton line 87 of: https://github.com/Varanda-Labs/gaupol/blob/mv/gaupol/waveview.py

Do you have a suggestion for a better communication? In Qt and I guess also for GObject we can connect class/instance to other class/instance without relationship as far as I remember.

Thanks in advance, MV

otsaloma commented 1 year ago

The way signals work in GTK (and which I have copied for the Observable class) is that objects emit signals with no regard to who might be interested. It's up to other objects then to "subscribe" to signals with the connect method.

So, here, if I understand correctly

  1. Waveview or GraphicArea should emit "request-seek" etc. which Application (probably in VideoAgent) or Page can then connect to, to do the corresponding video player or subtitle view updates.
  2. Making the GraphicArea respond to subtitle changes gets more complicated, but maybe you can reuse the same subtitle cache mechanism that already exists for the video player. It's perhaps not elegant, but it's already there and works. See

When the subtitle cache is updated: https://github.com/otsaloma/gaupol/blob/c75b4fb81567e9e2ee79fd1e09fd87ac8640d14a/gaupol/agents/video.py#L52-L57

The cache itself (start, end, text): https://github.com/otsaloma/gaupol/blob/c75b4fb81567e9e2ee79fd1e09fd87ac8640d14a/gaupol/agents/video.py#L374-L380

And how it's used to update subtitles in the video player: https://github.com/otsaloma/gaupol/blob/c75b4fb81567e9e2ee79fd1e09fd87ac8640d14a/gaupol/agents/video.py#L238-L253

The cache is basically the current texts of the current page. It gets updated in the video player on a 10 ms continuous loop.

Also, I don't think using singletons makes sense here. Application-level widgets should be instance attributes of the application, see the player widgets for comparison. Application-level widgets will be instantiated only once per application, so it's practically a singleton, but not technically.

mvaranda commented 1 year ago

Thanks a lot. I will check/digest these info once I have some time.

mvaranda commented 1 year ago

I did some more work this weekend:

https://rumble.com/v2l9ypa-gaupol-with-wave-widget-update-1.html

I may be done for now about features and integration. I may add a context menu for wave settings and will create a PR. Thanks for your help, MV

otsaloma commented 1 year ago

Looks good again so far.

One thing I notice is that you seem to be bypassing the undo-redo system, which is a problem. I'd recommend making the modifications on drag end with Project.set_start and Project.set_end. That way they're registered in the undo-redo system and users will have a consistent undo history. If I remember correctly, page.view should also automatically update via the signals if you use the proper set methods.

There are probably some other issues but I don't see anything major, those can be discussed in a PR line-by-line comments.

mvaranda commented 1 year ago

Good call, I believe that I fixed it now. You can double check, mv-progress-demo branch is updated. Next weekend I will try to wrap it up.

mvaranda commented 1 year ago

Hello Osmo,

Latest demo: https://rumble.com/v2meb2e-gaupol-with-wave-widget-update-2.html

I believe that I reached the completion of what I intend to do. There will be better ways to integrate my code with the overall application for complying with the architecture and designed. I would suggest you to make those changes as everything in your code is very organized. I may not have time or motivation to fully comply with the original design as it may lead to many back and forth interactions during PR review. Therefore, I would suggest the following:

Missing:

Thanks for your help and for creating this nice app. Cheers, MV

otsaloma commented 1 year ago

OK, thanks. There's now an "audio-waveform" branch you can do the PR against.

You might have noticed that I'm not interested in spending a lot of time on Gaupol anymore (#204), so I'm not going to do much work on this either. The audio waveform doesn't need to be in any way complete for the merge, but things that are implemented should work and fit right. I don't see any major issues, but probably a lot of smaller ones.

Language files are not an issue, I update those prior to releases. The only thing you need to do there is from aeidon.i18n import _ and then wrap UI strings in _("...").

mvaranda commented 1 year ago

Are you planning to do a new release?

otsaloma commented 1 year ago

Are you planning to do a new release?

There isn't much to release, just some translation commits, but those translations have been broken for maybe five years and no one complained apart from a translator, so it's probably no big issue. Is it the translations you're interested in or something else?