-
Notifications
You must be signed in to change notification settings - Fork 186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cue sheet support #457
base: devel
Are you sure you want to change the base?
Cue sheet support #457
Conversation
This change adds support for cuesheets by passing a track parameter around which indicates which track in the cuesheet should be played. The actual audio file is split with ffmpeg using the -ss and -t parameters, which are filled by the decoder when the file extension is '.cue'. cuesheet.py is added to parse cuesheets. This is taken from a separate project so it's a bit messy and contains some stuff that isn't used. Metadata is also fetched from the cuesheet per track.
Wow, that's really cool! You've worked through the full stack of CM to create that feature, very impressive indeed! :) I'll look through it on the weekend so we can get it merged soon 🍦 |
Hi @sn4kebite, I'm sorry, I didn't get to review your code yet! |
Hi, thanks for the response. If we can solve other issues by using another approach, I guess that's the way to go. However I didn't quite get what you mean; by duration, do you mean track length, or something like an time interval? Passing the start time should also work, as the cue sheet code could easily figure out which track the given time position belongs to (the last track that starts before or at the given time). I saw that there's already some references to |
Sorry, I didn't make myself too clear. What I mean is exactly what you mentioned: Using the I though it could be handled like so: So audiotranscode does not need to know anything about cuesheets... well actually nobody knows about cuesheets but the file-listing. Everything after that can be handled using start and end time of a track. |
Yeah, that sounds like what I was thinking. I've been playing around a bit with the code, and the only issue I see so far is that when fetching metainfo, we also need to know which track in the cue sheet to fetch metainfo for. This could be solved by passing Edit: Also, we still need to pass the filepath for the cue sheet instead of the audio file itself. The files does not necessarily have the same base name (you can have eg. foo.cue and bar.flac), so you need to know the filepath to the cue sheet; the audio filepath can easily be resolved by parsing the cue sheet. I currently added this parsing back into |
Current issues: * For file formats that CM doesn't know about, we don't know the length of the audio file, and thus can't fetch the length of the last track. * We should remove the duration flag when no duration is given, this is currently set to 100000 seconds when duration is None (unspecified). Other notes: * getsonginfo() needs to know which track is being fetched, this is currenly checked by comparing the provided starttime parameter with each track. This could be either left as-is, or done differently. * Decode.decode() must resolve the audio filepath itself, since we use the cue filepath to map to the proper decoder. The cue and audio files can also have different base names (eg. foo.cue can point to bar.flac). * starttime must include decimals to avoid playing back the last second or so of the previous track, duration also does this to stay consistent.
Okay, so I basically just replaced |
Yeah you're right, there is something I need to do before this can be solved elegantly: Allowing to pass meta-data directly into the filebrowser, instead of fetching it after the fact asynchronously. I didn't think of that. If you look inside I've opened another issue for the one thing that's left to do to make this work: after we show the correct meta-data in the file browser, they have to be passed to the playlist. Essentially that means not to call |
…esheet Conflicts: res/dist/cherrymusic.dist.js
This allows passing of metainfo for cuesheets without calling getsonginfo for every track. This gets rid of the starttime argument to getsonginfo, and allows us to pass the metainfo we already have when listing cuesheet contents without having to parse the cuesheet for every track. getsonginfo should now be called only once for all tracks.
So I never got around to finish this because of summer and stuff, but finally found the time to do so. The last commit lets |
Great, I'll try to look into it this evening 👍 |
Hi Jon, I'm sorry it toomk me so long to take a look on your code, but there are still multiple issues with it, and I didn't find enough the time for a review until lately. So let's break it up in parts: audiotranscodeYou a added a new type inside audiotranscode to handle the cue sheets, but audiotranscode should only take care of transcoding audio nothing else, just as you've noticed yourself. Additionally the cuesheet may contain all kinds of data not even supported by ffmpeg and therefore needs be handled in a different way. More on that later. I however recognise the problem of the cuesheetYour cuesheet module has some flaws: Your I like that you made sure that a cuesheet starting with a utf-8 BOM would be parsed correctly, but some comments would have helped to understand what's going on there. I wanted to use your module to try out some things myself, but I didn't understand the hierarchy of CDText, Descriptors and Tracks. I'd love to see some comments on top of the module to see how it can be used, how to iterate over a set of tracks and their meta-data etc. cherrymodelI have to admit that I don't know how the cuesheet format is specified, but to me it looks like your usage of the You are making the cuesheet to a very special case, while in reality it is not. It's just a playlist. It would be a lot more future proof, if you could just add a handler that takes care of all the files ending in 'cue' which then return a metainfoThe The general ProblemTo quote what I've said before
(emphasis added) In fact, I'd like to handle cuesheets and playlists (pls, m3u) in the same way folders are handled. You could then browse a cuesheet and select a single track, or add all tracks without accidentally selecting any other tracks from the same folder. I'm sorry if I haven't made that clear, but this is the only elegant way to handle this problem. I hope you understand all of my critique. I like to see when people like CM and I love it when people want to improve it. But I cannot accept patches that will make it harder to maintain the program, since we are already knee-deep in code-dept and we need to learn from our mistakes. Also I'd like to apologise again for not responding any quicker after you having made this much effort. In any case, I'd still like this feature to arrive in CM! |
I was just looking around and found this: http://digitalx.org/cue-sheet/examples/#example01 It might make for a good test-suite... |
Hey Jon, I have created new feature branch which contains a rough first version of cuesheet integration as I'd implement it. https://github.com/devsnd/cherrymusic/tree/feature_cuesheet I have completely rewritten the cuesheet parser, I hope you are not mad... 👊
I haven't changed anything in the frontend yet: everything works now by tricking the frontend into thinking the cuesheet is a folder and listing the files inside, which works really well. Next thing would be to integrate the changes you already made for the meta-info to be preloaded and not loaded again by the MediaBrowser, so that the titles, duration and so on are being shown correctly in the file browser. I seems you have already implemented everything needed there and I only have to cherrypick! 👍 I thought, instead of going through the transcoder first, we could instead make the frontend (the jplayer) do the work for us (skip x seconds, start next song after y seconds of playback) and care for the transcoding later. Maybe we can work together to finish this? 💃 🍦 |
Hi, sorry for the late reply. Treating the cuesheet like a directory actually sounds like a great idea. Also the cuesheet.py I added was taken from another small side-project I was working on some time ago, and badly needed some cleanup anyway. By having the frontend do the work, do you mean just delivering the file without caring for position in the transcoder (as in, deliver the entire file)? The cue type in the transcoder was added to deal with the track parameter and exotic filetypes. We can easily get rid of this type now that it uses starttime and duration by asking for the audiofile instead of the cue sheet, however any filetypes that aren't specifically supported won't work, and some decoders like the flac decoder needs some special attention to its arguments to work correctly (seems to need That aside I agree with the issues. And like I said in my initial post, I'm open for any changes. |
Great job getting the ball rolling, looks like cuesheet support is almost ready. Treating cuesheets like directories makes the most sense, I think, because we get to keep the interface simple. It also offers the chance of keeping the cuesheet logic very localized. What's the reason for letting the client handle start and end time offsets? I'm forgetting if seeking is a problem in the transcoder. Because if it's not, and if start and duration can become transcoder arguments, the client wouldn't need to care the slightest bit about where the audio is coming from. I agree it would be good to have some tests in place, as well as some precautions for unreadable/malformed .cue files. |
Essentially that's the problem right now; Because we support that many different programs to transcode and the syntax varies for all of them, it takes some time to make sure everything works as expected. It's somewhat easily solvable, but only adds problems to the issue at hand, i'd say.
Essentially yes. I thought going for the frontend first might be a good idea to get everything running; The server supports paritial HTTP requests and most sane file formats have a good way to handle seeking (i'm looking at you mp3!), so seeking on the client-side isn't such a great overhead. It's possible to instruct the jPlayer to just seek to any part of the stream, so lets use that. So essentially we're delivering the whole file, but jPlayer and HTTP 206 (and browser caching) take care of the rest for us for all natively supported file types. We can later than make transcoding work correctly. The issue with the transcoding and seeking within transcoded files then essentially boils down to issue #390 and #275. |
Hi, these commits adds support for cue sheets. These changes are based on some changes I did last summer but didn't have time to finish.
This works by adding some intrusive changes throughout the code, especially the transcoding and playlist parts. Most importantly it passes a track parameter around to indicate which track in the cue sheet should be played. The cue sheet is then parsed and the correct track is fetched, along with the proper time offset and length. The file pointed to by the cue sheet is then decoded with ffmpeg using these time codes.
The reason I'm going with ffmpeg here is that in theory you can provide pretty much any file format with cue sheets, and while the most common is FLAC, there are also some less popular formats such as TTA and TAK which are often used (TTA is fairly common in my case). This also adds another issue, which is missing audiolength for the last track when the format is unknown to cherrymusic; the first tracks uses the start time of the next track as their end time. I guess this could be solved with some ffmpeg magic, unless it's preferable to implement this natively in TinyTag (which I've so far only had a brief look at).
As far as I can see normal playback and transcoding is not affected (works for me), and all unit tests pass (yay), so there shouldn't be any issues for regular usage. Also I'm open for suggestions for any changes or other feedback.
Thanks,
Jon