I've added some more features including saving the state of the VSTi as an FXB file; encoding the tracks to WAV files and mixing them together.
Saving the VSTi State
Arcade has "kits" and I've used the BASS_VST_GetChunk and BASS_VST_SetChunk to dump everything as a binary file and then read back in. So this is the simplest type of implementation.
I added a menu to the second form that shows the Arcade VSTi plugin in all it's glory. once the file save name is picked I've called this function to write to file:
//pass path and filename
void getVSTStateAndWriteToFile(System::String^ fp, System::String^ initD, System::String^ fn) {
//Gets the VST plug-in state as a plain byte array (memory chunk storage).
void* chunk;
DWORD len;
chunk = BASS_VST_GetChunk(vststream, 0, &len);
String^ managedStr = gcnew String(fp);
pin_ptr<const wchar_t> wch = PtrToStringChars(managedStr);
std::wstring nativeWstr(wch);
std::ofstream f(wch, std::ios::binary | std::ios::trunc);
f.write(static_cast<char*>(chunk), len);
}
And then to read the chosen file use this:
void readFileAndSetVSTState(System::String^ fp)
{
//Sets the VST plug-in state with a plain byte array (memory chunk storage).
String^ managedStr = gcnew String(fp);
pin_ptr<const wchar_t> wch = PtrToStringChars(managedStr);
std::wstring nativeWstr(wch);
std::ifstream f(wch, std::ios::binary);
// get length of file
f.seekg(0, std::ios::end);
auto len = f.tellg();
f.seekg(0, std::ios::beg);
std::vector<char> chunk(len);
f.read(chunk.data(), len);
BASS_VST_SetChunk(vststream, 0, chunk.data(), len);
}
Encoding
I've decided to write out each individual track to a WAV file and then mix tracks together.
If you want to do this them you'll need the bassenc package and set up the lib, header file and dll like all the other bass add-ons.
Once set up you can save a track to WAV by adding the encoding to bassasio play so you can hear the track playing and record it to disk at the same time:
void playVSTi(int trackNumb) {
//pick the ASIO driver you want to use
if (!BASS_ASIO_Init(1, BASS_ASIO_THREAD)) // initialize ASIO device
MessageBox::Show("Can't initialize ASIO device");
outstream = BASS_StreamCreate(44100, 2, BASS_SAMPLE_FLOAT | BASS_STREAM_DECODE, VstStreamProc, NULL);
String^ trackPath = "C:\\Users\\timca\\Documents\\ArcadePlayer\\AudioOut\\track" + trackNumb.ToString() + ".wav";
char* tPath = (char*)Marshal::StringToHGlobalAnsi(trackPath).ToPointer();
//save to wav file
BASS_Encode_Start(outstream, tPath , BASS_ENCODE_PCM, 0, 0); // set a WAV writer on it
if (!BASS_ASIO_ChannelEnableBASS(FALSE, 0, outstream, TRUE))
MessageBox::Show("Can't enable ASIO channel(s)");
BASS_ChannelGetInfo(vststream, &i);
if (i.chans == 1) BASS_ASIO_ChannelEnableMirror(1, FALSE, 0); // mirror mono channel to form stereo output
BASS_ASIO_SetRate(i.freq); // try to set the device rate to avoid resampling
outstream = BASS_StreamCreate(44100, 2, BASS_SAMPLE_FLOAT, VstStreamProc, NULL); // create output
outpos = eventpos = 0; // playback positions
QWORD len = BASS_ChannelGetLength(midistream, BASS_POS_BYTE); // the length in bytes
time1 = BASS_ChannelBytes2Seconds(midistream, len); // the length in seconds
BASS_StreamFree(midistream);
// start the device using default buffer/latency
BASS_ASIO_Start(0, 0);
Application::UseWaitCursor = true;
System::Windows::Forms::Cursor::Current = Cursors::WaitCursor;
Sleep(time1 * 1000);
Application::UseWaitCursor = false;
System::Windows::Forms::Cursor::Current = Cursors::Default;
BASS_Encode_Stop(outstream); // stop the encoder
BASS_ASIO_Stop();
}
Finally if you want to add tracks into one you need to set up the mixer using bassmix (another add-on to load up!)
Simple set up a mixer and add the tracks to it, then encode to WAV file:
void playWavs() {
BASS_Init(-1, 44100, 0, 0, NULL);
HSTREAM mixer = BASS_Mixer_StreamCreate(44100, 2, BASS_SAMPLE_FLOAT);
BASS_ChannelPlay(mixer, 0);
// create decoders for each of the files
DWORD decoder1 = BASS_StreamCreateFile(FALSE, "C:\\Users\\timca\\Documents\\ArcadePlayer\\AudioOut\\track1.wav", 0, 0, BASS_SAMPLE_FLOAT | BASS_STREAM_DECODE);
DWORD decoder2 = BASS_StreamCreateFile(FALSE, "C:\\Users\\timca\\Documents\\ArcadePlayer\\AudioOut\\track2.wav", 0, 0, BASS_SAMPLE_FLOAT | BASS_STREAM_DECODE);
bool ok2 = BASS_Mixer_StreamAddChannel(mixer, decoder1, BASS_SAMPLE_FLOAT);
bool ok12 = BASS_Mixer_StreamAddChannel(mixer, decoder2, BASS_SAMPLE_FLOAT);
BASS_Encode_Start(mixer, "C:\\Users\\timca\\Documents\\ArcadePlayer\\AudioOut\\OutputMix.wav", BASS_ENCODE_PCM, NULL, 0); // set a WAV writer on the mixer
/// Get longest midi file length so recroding covers longest///////////////////////////
if (timeTrack1 < timeTrack2) {time1 = timeTrack2;}
else {time1 = timeTrack1;}
Application::UseWaitCursor = true;
System::Windows::Forms::Cursor::Current = Cursors::WaitCursor;
Sleep(time1 * 1000);
Application::UseWaitCursor = false;
System::Windows::Forms::Cursor::Current = Cursors::Default;
BASS_Encode_Stop(mixer); // close the WAV writer
FreeVSTChannelStream();
CleanupAndShutdown();
}
More next steps...
Save whole song to file (XML)
Read keys on the keyboard to play plugin
Add the macro and volume sliders
Add VU meters
Add more tracks and more rows to a track
Demo playing 2 tracks!
Коментари