-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Sample Track Recording Stage One #5990
base: master
Are you sure you want to change the base?
Conversation
🤖 Hey, I'm @LmmsBot from github.com/lmms/bot and I made downloads for this pull request, click me to make them magically appear! 🎩
Linux
Windows
macOS🤖{"platform_name_to_artifacts": {"Linux": [{"artifact": {"title": {"title": "(AppImage)", "platform_name": "Linux"}, "link": {"link": "https://output.circle-artifacts.com/output/job/a63b2a2d-f02b-4b83-8235-cdb92f29af95/artifacts/0/lmms-1.2.0-rc6.1231+gb2f3a1f86-linux-x86_64.AppImage"}}, "build_link": "https://circleci.com/gh/Reflexe/lmms/1626?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link"}], "Windows": [{"artifact": {"title": {"title": "64-bit", "platform_name": "Windows"}, "link": {"link": "https://output.circle-artifacts.com/output/job/0f86efe9-e3ad-4d7a-9f38-5831d542b9d2/artifacts/0/lmms-1.2.0-rc6.1231+gb2f3a1f86-mingw-win64.exe"}}, "build_link": "https://circleci.com/gh/Reflexe/lmms/1624?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link"}, {"artifact": {"title": {"title": "32-bit", "platform_name": "Windows"}, "link": {"link": "https://output.circle-artifacts.com/output/job/c724e479-cedb-48eb-affc-ba13fa6ce6fc/artifacts/0/lmms-1.2.0-rc6.1231+gb2f3a1f86-mingw-win32.exe"}}, "build_link": "https://circleci.com/gh/Reflexe/lmms/1628?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link"}, {"artifact": {"title": {"title": "32-bit", "platform_name": "Windows"}, "link": {"link": "https://ci.appveyor.com/api/buildjobs/m58xebqefwmpqok0/artifacts/build/lmms-1.3.0-alpha-msvc2017-win32.exe"}}, "build_link": "https://ci.appveyor.com/project/Lukas-W/lmms/builds/44344781"}, {"artifact": {"title": {"title": "64-bit", "platform_name": "Windows"}, "link": {"link": "https://ci.appveyor.com/api/buildjobs/2b35vlj7jhr3ov4a/artifacts/build/lmms-1.3.0-alpha-msvc2017-win64.exe"}}, "build_link": "https://ci.appveyor.com/project/Lukas-W/lmms/builds/44344781"}], "macOS": [{"artifact": {"title": {"title": "", "platform_name": "macOS"}, "link": {"link": "https://output.circle-artifacts.com/output/job/b8b29d25-eaf5-4b78-a156-eaec12fed67a/artifacts/0/lmms-1.2.0-rc6.1231+gb2f3a1f86-mac10.14.dmg"}}, "build_link": "https://circleci.com/gh/Reflexe/lmms/1627?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link"}]}, "commit_sha": "b2f3a1f86e95abb4f1565b7be86e69187028d028"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still going to review this with more care when I get home, but decided to take a peak at it from my phone and did a first pass review just for fixing code style (stuff like explicit blocks for one line ifs, spacing, camelCase variable names). Added all as suggestions if you'd like to just batch commit them.
Is there any reason you decided to use a braced-init-list instead of the expression-init-list for those new members?
My initial comments:
|
@PhysSong You are right. I forgot to remove it before pushing. |
Fully agree with doing backends 1-by-1. SDL is a good start since it's available everywhere and is the default, so recording will work ootb for most users. |
I compiled and ran this PR today on Linux and it seemed to work pretty well for me. Used the SDL backend (with pipewire), recorded a bit of Guitar music. Things that worked for me:
Things that did not work for me:
I think lmms tries to save the sample track, but it has no associated file name. See Another feature that would be really nice is if I had a way to save the sample track I recorded with lmms (maybe I decide I need it as an extra wav/mp3/something or want to post-process it somewhere else). All in all: A big plus from my side! Looking forward to seeing this feature integrated in lmms once it's done! |
@sebageek Thanks for the feedback. I will look into both. In any case. feel free to open an issue about being able to save individual Samples (if there isn't one open already).
|
Hey @Reflexe, nice to hear that it was helpful && that the second issue is easy to fix! I also opened #6022 for the feature request. Regarding the first issue: The record button apparently dates back to a stub implementation in 2008 and is only now appearing as it checks if the current audio backend is implementing capturing. So, how about using this button for its original intention? It could just allow the user to record samples without any other track playing (essentially the same as the two record buttons in the piano roll). On the other hand while I could imagine this functionality useful.. if this is not needed I'd opt for removing the button. |
I think you should remove |
I have compiled this branch ... I am about to PR that fix Issue #4668 , but also changes some things how capture works in goal to enable input capture callback only if needed. Also see my questions on Discord ... |
Now recording is working if merge this branch over my capture branch: RecordingStageOne.mp4Is this correct? |
4a62327
to
c14a357
Compare
Rebased on master, remove apply master gain related changes. |
c14a357
to
6158e76
Compare
I think at some point we should switch from set/clear record to a proper record button but that's for the future IG |
d01abd2
to
e5c795c
Compare
Tried doing this today, sadly it isn't working for me on Arch. When I place down a sample section then right click it, I get no "set/clear record" option at all. Would be really simple if I could grab the exe's in some way but none of the .exe's can be downloaded, same story with the appimage file. 2021-09-21.17-07-36.mp4 |
@Mayravixx That version doesn't contain the code from this PR - it's instead the latest |
audioPort as nullptr by default.
"played" (recorded).
actual data starts after that.
instead of hacking sampleBuffer ()->startFrame (). That solves a bug with `startFrame ()` being negetive in recording some cases.
Not only would there need to be upmixing for mono recording devices, but for audio input devices that have more than two channels, I'd appreciate the ability to pick which two channels are recorded for a stereo track as well as downmixing if more than two are selected. |
We now have #7567 , which seems to extend this PR to jack, which is really cool. I tested it, and with Jack, you get 0 latency (at least for me, I have setup jack with realtime prio). It might be a good idea to merge that PR into this PR here. From my tests, and consolidating that PR with this PR here, I see only 4 major issues:
Lastly, about SDL vs Jack: While I acknowledge that some like to use it for simplicity or for testing, SDL is usually not known as a professional backend, and I would not expect it to be realtime safe - I would expect latency issues. I am fine to merge the whole thing with Jack-Only, or with Jack and latency-or-broken-SDL. |
Also, another note about Jack mostly(?) being Linux (as discussed above): It's not a disadvantage for other back-ends, but rather an advantage IMO. Right now, if you want to add support for, let's say PortAudio, you would first need to read a 100 pages large PR, and in the end you would not be sure how many issues are in this PR and how soon it will get merged. If we consolidate a common framework for sample recording and merge it to master, all you would need to do is implement some virtuals in PortAudio.h and PortAudio.cpp - that is much easier than consolidating this WIP PR. |
I agree that it would make sense to merge #7567 in here. In that case there would already be two implementations that could be used to flesh out some general interface/framework regarding audio inputs. IMO such an interface should for example enable the users to select from all potential inputs in the application instead of letting them only select one in the settings dialog. Example: it should be possible to arm two tracks for recording, set one of the to record from "Input 1" and the other from "Input 2" and then record everything at once. |
So, what is the state about saving the record? IMO, this should not differ from the way we save non-recorded samples:
So all that is undefined for case 2 is where exactly we save such files (what directory, what naming)? Which also seems to have an answer:
As a default folder, I would propose "records/" in the LMMS main folder (next to "samples/"). |
Please note that all of the above only makes sense if the data is stored immediately into a file while being recorded. Implementing it like this is a large undertaking as it would result in a reimplementation of how LMMS handles samples and audio data. Currently LMMS simply holds all data in main memory. With this alternative implementation it would stream data from a pool of files into memory for playback and would also directly stream the data into files during recording. However, IMO the latter is the only "sane" implementation. Imagine recording some tracks, LMMS crashes (or the whole machine goes down for some reason) and you would not even have the raw recordings.
I propose a folder called "audio" in the LMMS main folder. To me "records" sounds like vinyl records. 😉 The naming pattern of REAPER is "Track Number-TrackName-Date_Time", e.g. "01-Guitar Left-250101_2114.wav". If a track does not have a name yet then it is omitted, e.g. "01-250101_2114.wav". |
I would not store it "immediately". The danger of LMMS crashing is usually solved by auto-saves. Losing your record is bad, but losing your project file is equally bad. So you keep it in memory and save it at the next autosave (and of course at the normal save procedure). Shouldn't this be an easy solution to the whole problem?
Then we have "audio/" and "samples/" in one folder. To me, this does not tell me the difference. Both is audio and both are samples 😄 |
Well, there's a difference between being able to at least quickly import the recorded audio files and recreate the project or to lose everything. I have just checked and REAPER seems to store the data in 512 KB chunks while recording them. IMO it makes sense to check how other similar software behaves because usually there's a reason. And if almost every DAW does something in a certain way it is very often not a good idea to invent something completely different. However, things can of course also be implemented incrementally.
To me "samples" has the connotation of rather short audio files that can be used in a sampler. And in the context of the LMMS structure of something that is shipped for that purpose. Into "audio" everything would go that's created by the users in the context of audio instead of MIDI, etc. Technically the borders are blurry of course. In many DAWs you can record some audio, process it, e.g. by trimming it, slicing it up, etc. and then drag the result into a sampler for sampler-like playback. Or you just copy them across the track, etc. |
My opinion: (Sample Track Recording) Stage One should not change:
P.S. [2] Record button enable stage one [3] Recorded audio placement in Sample Track [4] Audio recording format setting (dialog, configuration, ...) |
We should go LMMS way , and in "stage one" use shortest (less code lines - easy readable code) implementation variant .
My opinion:
But all this should be separated from this PR in improvement issue "Audio mixing project in external folder". |
I want to point out that #7627 is a workaround / solution for recordings saving dilemma presented here. |
How I understand , in this case audio should be recorded in memory and, after recording stopped, sample export dialog should be opened ... Anyway it is good variant for stage one. |
Why not? It is a relatively large new feature which needs to somehow organize data that is created on-the-fly. So it would be a bit surprising to me if it would not have an impact on the project file or the folder structure.
I am not sure if is a good idea to have sub folders which are named like the tracks. It's just one more layer that might go out of sync. Imagine the following scenario:
What should now happen? Should the folder also be renamed? If no, then it might quickly become unwieldy for the users due to the differences. If yes, what is really gained by this? To me it just seems like some additional unnecessary complexity.
It would go to a folder where we already store other user created/related data.
Where should it be discussed if not here?
Both implementation will have their challenges if implemented correctly. The first thing to notice is that the audio data comes in via the real-time audio thread. However, both implementation will trigger actions that must not be done on the audio thread:
A "classic" text on the topic: "Real-time audio programming 101: time waits for nothing" |
For final variant - yes. For stage one - no: only one thing be added - samples to sample track not only imported, but may be recorded too. My opinion: this PR problem is that stage one is treated as last one. Why it is problem? LMMS device drivers are not ready to final variant - but device drivers can not be improved without testing possible: are waiting for this stage one be in master.
So in this case there are no difference in complexity (only variant):
(All after I treat as off-topic)
I mean folder is in track configuration, so changes the file name pattern.
OK, but
In PR "Sample Track Recording Stage Five - Final" . P.S. |
I mean, there is a way to have audio recording working in most common audio backend used in LMMS, SDL. There is also proposed solution for saving recordings, without writing base64 blob into project file. Rudimentary, but it is. Other stuff, like recording in other audio API (JACK is already in another PR), autosaving, project folders, can be done later. |
OK, I compiled this PR (but only for my Linux Debian Stable 64-bit). It seems, that audio is recorded to memory and saved in project file as huge data="...." line . In this case #7627 is a workaround , but it should be tested. Now I will check, how Audio Recording is implemented ... P.S. |
@JohannesLorenz, I have just checked with Bitwig. In the project folder there is a sub folder called "recordings" where the files go that have been recorded with Bitwig. There's also a sub folder called "samples" where the samples go that come from somewhere else, e.g. samples that have been loaded from disk and which are used in a drum machine. Perhaps this is some nice compromise so that we still do not have any vinyls in our folders. 😉 |
It seems that #7627 only exports the content of sample clips into files, i.e. it will not replace the recorded data with references to the exported files. This means that the data would still be stored in unwieldy Saving the data as Example for several versions:
|
Sorry, I don't understand what you're trying to say. Can you please elaborate? |
I meant to say that relying on the auto-save feature might lead to losing lot of work if the auto-save is not "quick" enough, e.g. if you have done a lot of recordings between the last auto-save point and the next one that is not reached anymore due to a crash. If the recordings are streamed to disk then you will have at least all your recordings and might only lose part of some recordings if LMMS crashes during the recording. The auto-save files are also another example where storing everything in memory and then in |
I have just also checked how Bitwig handles projects which have not been saved yet. The are assigned a GUID as the "project name" and their data is stored in a temporary folder, e.g. the recordings are stored under I guess if you then save a project for the first time then all that stuff is moved into the actual project folder together with a newly created save file. |
The same accounts for the rest of the project file, too. I assume you say that it's more easy to create the notes and the instrument/effect tunings of the last 1 hour than the records of the last 1 hour? In this case, we could allow 2 autosave options (How often should records be saved? How often should the rest be saved). However, I am not against the proposal of saving it while recording - it's just more overhead to code that 😬 Possibly the audio thread would smash everything into a ringbuffer, and another thread fetches it and writes it on disk. I imagine it's more ugly to split the data into chunks and find a good naming for those chunks. At this point though, I am also not sure why we should split it... |
I would like to mention that I have made 3 PRs about audio exporting:
I would suggest moving the discussions about project folders to #7538 (since that pull request is a project folder implementation) |
It is 1-st thing, that should be implemented and it is surprise for me that it is not done yet ... P.S. But about question: "Where and how place recorded files?" |
recording.mov
This is the first stage of the Sample Track Recording feature and was intended to only work on one backend (SDL) with no fancy features like looping and visualization.
It has been tested very quickly on my setup with a monitor interface.
Note: the changes are from #4994.