View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0000501 | OpenMPT | Feature Request | public | 2014-04-03 20:31 | 2021-04-16 08:40 |
Reporter | coda | Assigned To | manx | ||
Priority | normal | Severity | minor | Reproducibility | have not tried |
Status | acknowledged | Resolution | open | ||
Target Version | OpenMPT 1.?? (long term goals) | ||||
Summary | 0000501: Audio recording to sample | ||||
Description | Non-trivial feature but a long-term goal that would prove very useful. Rationale: FT2 and Renoise both have various methods to create sample data from within the tracker. They're still definitely trackers and not DAWs, although Renoise gets a bit close with its pattern-syncing. OpenMPT only allows importing external samples or creating sample data with the pencil tool. My approach would be to minimize the amount of extra UI needed:
This allows for recording live audio along with a pattern at any point, as well as splitting a recording across multiple samples that are all armed. This could also be a starting point for routing parts of the graph back to the input for a Freeze/"Sample VSTi" feature (another useful thing in Renoise, which is made more necessary by its utter lack of tracker-style pitch control on VSTis). I provided a proof-of-concept patch which implements this sort of behavior - with, of course, no error checking or UI (naming a sample starting with '%' arms it, only ASIO is supported, the sample must have some initial data and be triggered at the playback rate and have a 16-bit mono format). | ||||
Tags | No tags attached. | ||||
Has the bug occurred in previous versions? | |||||
Tested code revision (in case you know it) | |||||
samplerecord.patch (5,940 bytes)
Index: sounddev/SoundDevice.h =================================================================== --- sounddev/SoundDevice.h (revision 3634) +++ sounddev/SoundDevice.h (working copy) @@ -248,6 +248,7 @@ uint32 UpdateIntervalMS; uint32 Samplerate; uint8 Channels; + uint8 InChannels; SampleFormat sampleFormat; bool ExclusiveMode; // Use hardware buffers directly bool BoostThreadPriority; // Boost thread priority for glitch-free audio rendering @@ -261,6 +262,7 @@ , UpdateIntervalMS(5) , Samplerate(48000) , Channels(2) + , InChannels(2) , sampleFormat(SampleFormatFloat32) , ExclusiveMode(false) , BoostThreadPriority(true) Index: sounddev/SoundDeviceASIO.cpp =================================================================== --- sounddev/SoundDeviceASIO.cpp (revision 3634) +++ sounddev/SoundDeviceASIO.cpp (working copy) @@ -322,11 +322,11 @@ ASSERT(false); } - m_BufferInfo.resize(m_Settings.Channels); - for(int channel = 0; channel < m_Settings.Channels; ++channel) + m_BufferInfo.resize(m_Settings.Channels + m_Settings.InChannels); + for(int channel = 0; channel < m_Settings.Channels + m_Settings.InChannels; ++channel) { MemsetZero(m_BufferInfo[channel]); - m_BufferInfo[channel].isInput = ASIOFalse; + m_BufferInfo[channel].isInput = channel < m_Settings.Channels ? ASIOFalse : ASIOTrue; m_BufferInfo[channel].channelNum = m_Settings.ChannelMapping.ToDevice(channel); } m_Callbacks.bufferSwitch = CallbackBufferSwitch; @@ -336,20 +336,20 @@ ALWAYS_ASSERT(g_CallbacksInstance == nullptr); g_CallbacksInstance = this; Log(mpt::String::Print("ASIO: createBuffers(numChannels=%1, bufferSize=%2)", m_Settings.Channels, m_nAsioBufferLen)); - asioCall(createBuffers(&m_BufferInfo[0], m_Settings.Channels, m_nAsioBufferLen, &m_Callbacks)); + asioCall(createBuffers(&m_BufferInfo[0], m_Settings.Channels + m_Settings.InChannels, m_nAsioBufferLen, &m_Callbacks)); m_BuffersCreated = true; - m_ChannelInfo.resize(m_Settings.Channels); - for(int channel = 0; channel < m_Settings.Channels; ++channel) + m_ChannelInfo.resize(m_Settings.Channels + m_Settings.InChannels); + for(int channel = 0; channel < m_Settings.Channels + m_Settings.InChannels; ++channel) { MemsetZero(m_ChannelInfo[channel]); - m_ChannelInfo[channel].isInput = ASIOFalse; + m_ChannelInfo[channel].isInput = channel < m_Settings.Channels ? ASIOFalse : ASIOTrue; m_ChannelInfo[channel].channel = m_Settings.ChannelMapping.ToDevice(channel); asioCall(getChannelInfo(&m_ChannelInfo[channel])); ASSERT(m_ChannelInfo[channel].isActive); mpt::String::SetNullTerminator(m_ChannelInfo[channel].name); Log(mpt::String::Print("ASIO: getChannelInfo(isInput=%1 channel=%2) => isActive=%3 channelGroup=%4 type=%5 name='%6'" - , ASIOFalse + , m_ChannelInfo[channel].isInput , m_Settings.ChannelMapping.ToDevice(channel) , m_ChannelInfo[channel].isActive , m_ChannelInfo[channel].channelGroup @@ -361,7 +361,7 @@ bool allChannelsAreFloat = true; bool allChannelsAreInt16 = true; bool allChannelsAreInt24 = true; - for(int channel = 0; channel < m_Settings.Channels; ++channel) + for(int channel = 0; channel < m_Settings.Channels + m_Settings.InChannels; ++channel) { if(!IsSampleTypeFloat(m_ChannelInfo[channel].type)) { Index: sounddev/SoundDeviceASIO.h =================================================================== --- sounddev/SoundDeviceASIO.h (revision 3634) +++ sounddev/SoundDeviceASIO.h (working copy) @@ -30,12 +30,15 @@ { friend class TemporaryASIODriverOpener; +public: + std::vector<ASIOBufferInfo> m_BufferInfo; + long m_BufferIndex; protected: IASIO *m_pAsioDrv; long m_nAsioBufferLen; - std::vector<ASIOBufferInfo> m_BufferInfo; + ASIOCallbacks m_Callbacks; static CASIODevice *g_CallbacksInstance; // only 1 opened instance allowed for ASIO bool m_BuffersCreated; @@ -48,7 +51,7 @@ bool m_DeviceRunning; uint64 m_TotalFramesWritten; - long m_BufferIndex; + LONG m_RenderSilence; LONG m_RenderingSilence; Index: soundlib/Sndmix.cpp =================================================================== --- soundlib/Sndmix.cpp (revision 3634) +++ soundlib/Sndmix.cpp (working copy) @@ -141,6 +141,20 @@ } +#include "..\sounddev\SoundDevice.h" +#include "..\sounddev\SoundDevices.h" + +#include "..\sounddev\SoundDeviceASIO.h" + +#include "../common/misc_util.h" +#include "../common/StringFixer.h" +#include "../soundlib/SampleFormatConverters.h" + +#include "..\mptrack\MainFrm.h" + +#include "modsmp_ctrl.h" + + CSoundFile::samplecount_t CSoundFile::Read(samplecount_t count, IAudioReadTarget &target) //--------------------------------------------------------------------------------------- { @@ -225,6 +239,20 @@ m_Reverb.Process(MixSoundBuffer, countChunk); #endif // NO_REVERB + + for(int chn=0;chn<MAX_CHANNELS;chn++) + if(Chn[chn].pCurrentSample && Chn[chn].nInc == 0x10000 && Chn[chn].pModSample && Chn[chn].pModSample->filename[0] == '%') { + CASIODevice *sda = dynamic_cast<CASIODevice*>(CMainFrame::GetMainFrame()->gpSoundDevice); + if(sda) { + if(Chn[chn].nPos >= Chn[chn].pModSample->nLength - countChunk) + ctrlSmp::InsertSilence( *Chn[chn].pModSample, Chn[chn].pModSample->nLength, Chn[chn].pModSample->nLength, *this); + + + CopyInterleavedToChannel<SC::Convert<int16, int32> >(reinterpret_cast<int16*>(const_cast<void*>(Chn[chn].pCurrentSample)) + Chn[chn].nPos, reinterpret_cast<int32*>(sda->m_BufferInfo[2].buffers[1 - sda->m_BufferIndex]) , 1, countChunk, 0); + //CopyInterleavedToChannel<SC::Convert<int16, int32> >(reinterpret_cast<int16*>(Samples[1].pSample) + (m_lTotalSampleCount % (Samples[1].nLength - 1024)), reinterpret_cast<int32*>(sda->m_BufferInfo[2].buffers[1 - sda->m_BufferIndex]) , 1, countChunk, 0); + } + } + if(mixPlugins) { ProcessPlugins(countChunk); |
|
Now that we have builtin plugins and some potential device input support it occurred to me the quickest path to exposing input would probably be something like the Audio version of Midi I/O (minus the O?). Might not need any params at all - just copy input into master/the next plugin in the graph. |
|
So you're looking for the feature commonly known as "bouncing"? |
|
No, this feature request is about audio input. OpenMPT can already bounce tracks. |
|
I do not think that would be easy to implement. |
|
What I have in mind is along the lines of the following (just sketching ideas right now, there is no implementation yet, an honestly there are more internal refactorings that I would like to see before even starting an implementation of recording):
|
|
Date Modified | Username | Field | Change |
---|---|---|---|
2014-04-03 20:31 | coda | New Issue | |
2014-04-03 20:31 | coda | File Added: samplerecord.patch | |
2014-08-14 10:49 | manx | Assigned To | => manx |
2014-08-14 10:49 | manx | Status | new => acknowledged |
2014-08-14 10:50 | manx | Target Version | => OpenMPT 1.24.01.00 / libopenmpt 0.2-beta8 (upgrade first) |
2014-12-12 00:02 | Saga Musix | Target Version | OpenMPT 1.24.01.00 / libopenmpt 0.2-beta8 (upgrade first) => OpenMPT 1.?? (long term goals) |
2015-11-07 17:18 | manx | Relationship added | parent of 0000722 |
2018-01-29 02:00 | coda | Note Added: 0003397 | |
2018-01-29 06:20 | StarWolf3000 | Note Added: 0003398 | |
2018-01-29 07:13 | coda | Note Added: 0003399 | |
2018-01-30 16:25 | manx | Note Added: 0003402 | |
2018-01-30 16:36 | manx | Note Added: 0003403 | |
2018-05-18 07:11 | manx | Relationship added | related to 0001042 |
2021-04-16 08:40 | Saga Musix | Relationship added | has duplicate 0001448 |