diff options
author | Wohlstand <admin@wohlnet.ru> | 2017-10-18 03:03:49 +0300 |
---|---|---|
committer | Wohlstand <admin@wohlnet.ru> | 2017-10-18 03:03:49 +0300 |
commit | bb3fc091e0a5b9d1faa9198f3a72d1d332ddc85f (patch) | |
tree | f045915520ff7785a7f8c4f583de6a2a279e1a1d /src | |
parent | 380d08e1a234efb17cf15a6b6c2d00c52e4fc648 (diff) | |
download | libADLMIDI-bb3fc091e0a5b9d1faa9198f3a72d1d332ddc85f.tar.gz libADLMIDI-bb3fc091e0a5b9d1faa9198f3a72d1d332ddc85f.tar.bz2 libADLMIDI-bb3fc091e0a5b9d1faa9198f3a72d1d332ddc85f.zip |
Wave recording in demo tool and disable loop by default
Diffstat (limited to 'src')
-rw-r--r-- | src/adlmidi.cpp | 5 | ||||
-rw-r--r-- | src/adlmidi.h | 2 | ||||
-rw-r--r-- | src/adlmidi_midiplay.cpp | 8 | ||||
-rw-r--r-- | src/midiplay/Makefile | 12 | ||||
-rw-r--r-- | src/midiplay/adlmidiplay.cpp | 144 | ||||
-rwxr-xr-x | src/midiplay/wave_writer.c | 170 | ||||
-rwxr-xr-x | src/midiplay/wave_writer.h | 21 |
7 files changed, 312 insertions, 50 deletions
diff --git a/src/adlmidi.cpp b/src/adlmidi.cpp index 11b7c9b..d16fab5 100644 --- a/src/adlmidi.cpp +++ b/src/adlmidi.cpp @@ -40,7 +40,7 @@ ADLMIDI_EXPORT struct ADL_MIDIPlayer *adl_init(long sample_rate) midi_device->AdlPercussionMode = 0; midi_device->LogarithmicVolumes = 0; midi_device->SkipForward = 0; - midi_device->QuitWithoutLooping = 0; + midi_device->loopingIsEnabled = 0; midi_device->ScaleModulators = 0; midi_device->delay = 0.0; midi_device->carry = 0.0; @@ -177,8 +177,7 @@ ADLMIDI_EXPORT void adl_setScaleModulators(ADL_MIDIPlayer *device, int smod) ADLMIDI_EXPORT void adl_setLoopEnabled(ADL_MIDIPlayer *device, int loopEn) { if(!device) return; - - device->QuitWithoutLooping = (loopEn == 0); + device->loopingIsEnabled = (loopEn != 0); } ADLMIDI_EXPORT void adl_setLogarithmicVolumes(struct ADL_MIDIPlayer *device, int logvol) diff --git a/src/adlmidi.h b/src/adlmidi.h index 5aa913b..c82ef63 100644 --- a/src/adlmidi.h +++ b/src/adlmidi.h @@ -49,7 +49,7 @@ struct ADL_MIDIPlayer unsigned int LogarithmicVolumes; int VolumeModel; unsigned int SkipForward; - unsigned int QuitWithoutLooping; + unsigned int loopingIsEnabled; unsigned int ScaleModulators; double delay; double carry; diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index 3b9d396..d473806 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -905,7 +905,7 @@ bool MIDIplay::ProcessEvents() //Loop if song end or loop end point has reached loopEnd = false; shortest = 0; - if(opl._parent->QuitWithoutLooping != 0) + if(opl._parent->loopingIsEnabled == 0) { atEnd = true; //Don't handle events anymore CurrentPosition.wait += 1.0;//One second delay until stop playing @@ -952,8 +952,8 @@ void MIDIplay::HandleEvent(size_t tk) if(evtype == 6) { - //Turn on/off Loop handling - if(opl._parent->QuitWithoutLooping == 0) + //Turn on/off Loop handling when loop is disabled + if(opl._parent->loopingIsEnabled != 0) { /* Move this away from events handler */ for(size_t i = 0; i < data.size(); i++) @@ -1058,7 +1058,7 @@ void MIDIplay::HandleEvent(size_t tk) uint8_t ctrlno = TrackData[tk][CurrentPosition.track[tk].ptr++]; uint8_t value = TrackData[tk][CurrentPosition.track[tk].ptr++]; - if((opl._parent->QuitWithoutLooping == 0) && (ctrlno == 111) && !invalidLoop) + if((opl._parent->loopingIsEnabled != 0) && (ctrlno == 111) && !invalidLoop) { loopStart = true; loopStart_passed = true; diff --git a/src/midiplay/Makefile b/src/midiplay/Makefile index 8b8e85f..f2512b4 100644 --- a/src/midiplay/Makefile +++ b/src/midiplay/Makefile @@ -1,4 +1,12 @@ all: midiplay -midiplay: adlmidiplay.cpp - g++ $^ -Wl,-rpath='$$ORIGIN' -I.. -L../../bin -ladlmidi -lSDL2 -o ../../bin/adlmidiplay + +midiplay: adlmidiplay.o wave_writer.o + g++ $^ -Wl,-rpath='$$ORIGIN' -L../../bin -ladlmidi -lSDL2 -o ../../bin/adlmidiplay + rm *.o + +adlmidiplay.o: adlmidiplay.cpp + g++ -c $^ -I.. -o adlmidiplay.o + +wave_writer.o: wave_writer.c + gcc -c $^ -I.. -o wave_writer.o diff --git a/src/midiplay/adlmidiplay.cpp b/src/midiplay/adlmidiplay.cpp index cbea468..f2781f2 100644 --- a/src/midiplay/adlmidiplay.cpp +++ b/src/midiplay/adlmidiplay.cpp @@ -5,10 +5,14 @@ #include <cstdlib> #include <cstring> #include <deque> +#include <signal.h> +#define SDL_MAIN_HANDLED #include <SDL2/SDL.h> #include <adlmidi.h> +#include "wave_writer.h" + class MutexType { SDL_mutex *mut; @@ -40,8 +44,9 @@ static void SDL_AudioCallbackX(void *, Uint8 *stream, int len) /*if(len != AudioBuffer.size()) fprintf(stderr, "len=%d stereo samples, AudioBuffer has %u stereo samples", len/4, (unsigned) AudioBuffer.size()/2);*/ - unsigned ate = len / 2; // number of shorts - if(ate > AudioBuffer.size()) ate = AudioBuffer.size(); + unsigned ate = (unsigned)len / 2; // number of shorts + if(ate > AudioBuffer.size()) + ate = (unsigned)AudioBuffer.size(); for(unsigned a = 0; a < ate; ++a) { target[a] = AudioBuffer[a]; @@ -64,10 +69,15 @@ static void printError(const char *err) std::fflush(stderr); } -#undef main -int main(int argc, char **argv) +static int stop = 0; +static void sighandler(int dum) { + if((dum == SIGINT) || (dum == SIGHUP) || (dum == SIGTERM)) + stop = 1; +} +int main(int argc, char **argv) +{ if(argc < 2 || std::string(argv[1]) == "--help" || std::string(argv[1]) == "-h") { std::printf( @@ -87,7 +97,7 @@ int main(int argc, char **argv) ); int banksCount = adl_getBanksCount(); - const char* const* banknames = adl_getBankNames(); + const char *const *banknames = adl_getBankNames(); if(banksCount > 0) { @@ -108,7 +118,9 @@ int main(int argc, char **argv) " Miles four-op set requires the maximum of numcards*6.\n" "\n" ); - } else { + } + else + { std::printf(" This build of libADLMIDI has no embedded banks!\n\n"); } @@ -134,17 +146,6 @@ int main(int argc, char **argv) spec.samples = Uint16((double)spec.freq * AudioBufferLength); spec.callback = SDL_AudioCallbackX; - // Set up SDL - if(SDL_OpenAudio(&spec, &obtained) < 0) - { - std::fprintf(stderr, "\nERROR: Couldn't open audio: %s\n\n", SDL_GetError()); - //return 1; - } - if(spec.samples != obtained.samples) - std::fprintf(stderr, "Wanted (samples=%u,rate=%u,channels=%u); obtained (samples=%u,rate=%u,channels=%u)\n", - spec.samples, spec.freq, spec.channels, - obtained.samples, obtained.freq, obtained.channels); - ADL_MIDIPlayer *myDevice; myDevice = adl_init(44100); if(myDevice == NULL) @@ -153,6 +154,9 @@ int main(int argc, char **argv) return 1; } + bool recordWave = false; + + adl_setLoopEnabled(myDevice, 1); while(argc > 2) { @@ -162,6 +166,11 @@ int main(int argc, char **argv) adl_setPercMode(myDevice, 1); else if(!std::strcmp("-v", argv[2])) adl_setHVibrato(myDevice, 1); + else if(!std::strcmp("-w", argv[2])) + { + recordWave = true; + adl_setLoopEnabled(myDevice, 0);//Disable loop while record WAV + } else if(!std::strcmp("-t", argv[2])) adl_setHTremolo(myDevice, 1); else if(!std::strcmp("-nl", argv[2])) @@ -175,6 +184,24 @@ int main(int argc, char **argv) argc -= (had_option ? 2 : 1); } + if(!recordWave) + { + // Set up SDL + if(SDL_OpenAudio(&spec, &obtained) < 0) + { + std::fprintf(stderr, "\nERROR: Couldn't open audio: %s\n\n", SDL_GetError()); + std::fflush(stderr); + //return 1; + } + if(spec.samples != obtained.samples) + { + std::fprintf(stderr, "Wanted (samples=%u,rate=%u,channels=%u); obtained (samples=%u,rate=%u,channels=%u)\n", + spec.samples, spec.freq, spec.channels, + obtained.samples, obtained.freq, obtained.channels); + std::fflush(stderr); + } + } + if(argc >= 3) { if(is_number(argv[2])) @@ -183,7 +210,7 @@ int main(int argc, char **argv) if(adl_setBank(myDevice, bankno) != 0) { printError(adl_errorString()); - return 0; + return 1; } } else @@ -195,7 +222,7 @@ int main(int argc, char **argv) std::fprintf(stdout, "FAILED!\n"); std::fflush(stdout); printError(adl_errorString()); - return 0; + return 1; } std::fprintf(stdout, "OK!\n"); std::fflush(stdout); @@ -207,7 +234,7 @@ int main(int argc, char **argv) if(adl_setNumCards(myDevice, std::atoi(argv[3])) != 0) { printError(adl_errorString()); - return 0; + return 1; } std::fprintf(stdout, "Number of cards %s\n", argv[3]); } @@ -217,7 +244,7 @@ int main(int argc, char **argv) if(adl_setNumCards(myDevice, 4) != 0) { printError(adl_errorString()); - return 0; + return 1; } } @@ -226,7 +253,7 @@ int main(int argc, char **argv) if(adl_setNumFourOpsChn(myDevice, std::atoi(argv[4])) != 0) { printError(adl_errorString()); - return 0; + return 1; } std::fprintf(stdout, "Number of four-ops %s\n", argv[4]); } @@ -237,31 +264,68 @@ int main(int argc, char **argv) return 2; } - SDL_PauseAudio(0); + signal(SIGINT, sighandler); + signal(SIGHUP, sighandler); + signal(SIGTERM, sighandler); - while(1) + if(!recordWave) { - short buff[4096]; - size_t got = (size_t)adl_play(myDevice, 4096, buff); - if(got <= 0) - break; - - AudioBuffer_lock.Lock(); - size_t pos = AudioBuffer.size(); - AudioBuffer.resize(pos + got); - for(size_t p = 0; p < got; ++p) - AudioBuffer[pos + p] = buff[p]; - AudioBuffer_lock.Unlock(); - - const SDL_AudioSpec &spec = obtained; - while(AudioBuffer.size() > spec.samples + (spec.freq * 2) * OurHeadRoomLength) + SDL_PauseAudio(0); + + while(!stop) { - SDL_Delay(1); + short buff[4096]; + size_t got = (size_t)adl_play(myDevice, 4096, buff); + if(got <= 0) + break; + + AudioBuffer_lock.Lock(); + size_t pos = AudioBuffer.size(); + AudioBuffer.resize(pos + got); + for(size_t p = 0; p < got; ++p) + AudioBuffer[pos + p] = buff[p]; + AudioBuffer_lock.Unlock(); + + const SDL_AudioSpec &spec = obtained; + while(AudioBuffer.size() > spec.samples + (spec.freq * 2) * OurHeadRoomLength) + { + SDL_Delay(1); + } + } + + SDL_CloseAudio(); + } + else + { + std::string wave_out = std::string(argv[1]) + ".wav"; + std::fprintf(stdout, "Recording WAV file %s...\n", wave_out.c_str()); + std::fflush(stdout); + + if(wave_open(spec.freq, wave_out.c_str()) == 0) + { + wave_enable_stereo(); + while(!stop) + { + short buff[4096]; + size_t got = (size_t)adl_play(myDevice, 4096, buff); + if(got <= 0) + break; + wave_write(buff, (long)got); + } + wave_close(); + + std::fprintf(stdout, "Completed!\n"); + std::fflush(stdout); + } + else + { + adl_close(myDevice); + return 1; } } adl_close(myDevice); - SDL_CloseAudio(); + return 0; } diff --git a/src/midiplay/wave_writer.c b/src/midiplay/wave_writer.c new file mode 100755 index 0000000..e2c9611 --- /dev/null +++ b/src/midiplay/wave_writer.c @@ -0,0 +1,170 @@ +/* snes_spc 0.9.0. http://www.slack.net/~ant/ */ + +#include "wave_writer.h" + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> + +#ifdef MUSPLAY_USE_WINAPI +#include <windows.h> +#endif + +/* Copyright (C) 2003-2007 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +enum { buf_size = 32768 * 2 }; +enum { header_size = 0x2C }; + +typedef short sample_t; + +static unsigned char* buf; +static FILE* file; +static long sample_count_; +static long sample_rate_; +static long buf_pos; +static int chan_count; + +static void exit_with_error( const char* str ) +{ + fprintf(stderr, "WAVE Writer Error: %s\n", str ); + fflush(stderr); +} + +int wave_open( long sample_rate, const char* filename ) +{ + sample_count_ = 0; + sample_rate_ = sample_rate; + buf_pos = header_size; + chan_count = 1; + + buf = (unsigned char*) malloc( buf_size * sizeof *buf ); + if ( !buf ) + { + exit_with_error( "Out of memory" ); + return -1; + } + +#ifndef MUSPLAY_USE_WINAPI + file = fopen( filename, "wb" ); +#else + wchar_t widePath[MAX_PATH]; + int size = MultiByteToWideChar(CP_UTF8, 0, filename, strlen(filename), widePath, MAX_PATH); + widePath[size] = '\0'; + file = _wfopen( widePath, L"wb" ); +#endif + if (!file) + { + exit_with_error( "Couldn't open WAVE file for writing" ); + return -1; + } + + setvbuf( file, 0, _IOFBF, 32 * 1024L ); + return 0; +} + +void wave_enable_stereo( void ) +{ + chan_count = 2; +} + +static void flush_() +{ + if ( buf_pos && !fwrite( buf, (size_t)buf_pos, 1, file ) ) + exit_with_error( "Couldn't write WAVE data" ); + buf_pos = 0; +} + +void wave_write( short const* in, long remain ) +{ + sample_count_ += remain; + while ( remain ) + { + if ( buf_pos >= buf_size ) + flush_(); + + { + unsigned char* p = &buf [buf_pos]; + long n = (buf_size - (unsigned long)buf_pos) / sizeof (sample_t); + if ( n > remain ) + n = remain; + remain -= n; + + /* convert to LSB first format */ + while ( n-- ) + { + int s = *in++; + *p++ = (unsigned char) s & (0x00FF); + *p++ = (unsigned char) (s >> 8) & (0x00FF); + } + + buf_pos = p - buf; + assert( buf_pos <= buf_size ); + } + } +} + +long wave_sample_count( void ) +{ + return sample_count_; +} + +static void set_le32( void* p, unsigned long n ) +{ + ((unsigned char*) p) [0] = (unsigned char) n & (0xFF); + ((unsigned char*) p) [1] = (unsigned char) (n >> 8) & (0xFF); + ((unsigned char*) p) [2] = (unsigned char) (n >> 16) & (0xFF); + ((unsigned char*) p) [3] = (unsigned char) (n >> 24) & (0xFF); +} + +void wave_close( void ) +{ + if ( file ) + { + /* generate header */ + unsigned char h [header_size] = + { + 'R','I','F','F', + 0,0,0,0, /* length of rest of file */ + 'W','A','V','E', + 'f','m','t',' ', + 0x10,0,0,0, /* size of fmt chunk */ + 1,0, /* uncompressed format */ + 0,0, /* channel count */ + 0,0,0,0, /* sample rate */ + 0,0,0,0, /* bytes per second */ + 0,0, /* bytes per sample frame */ + 16,0, /* bits per sample */ + 'd','a','t','a', + 0,0,0,0, /* size of sample data */ + /* ... */ /* sample data */ + }; + long ds = sample_count_ * (long)sizeof (sample_t); + int frame_size = chan_count * (long)sizeof (sample_t); + + set_le32( h + 0x04, header_size - 8 + ds ); + h [0x16] = (unsigned char)chan_count; + set_le32( h + 0x18, (unsigned long)sample_rate_ ); + set_le32( h + 0x1C, (unsigned long)sample_rate_ * (unsigned long)frame_size ); + h [0x20] = (unsigned char)frame_size; + set_le32( h + 0x28, (unsigned long)ds ); + + flush_(); + + /* write header */ + fseek( file, 0, SEEK_SET ); + fwrite( h, header_size, 1, file ); + fclose( file ); + file = 0; + free( buf ); + buf = 0; + } +} diff --git a/src/midiplay/wave_writer.h b/src/midiplay/wave_writer.h new file mode 100755 index 0000000..6d49718 --- /dev/null +++ b/src/midiplay/wave_writer.h @@ -0,0 +1,21 @@ +/* WAVE sound file writer for recording 16-bit output during program development */ + +#pragma once +#ifndef WAVE_WRITER_H +#define WAVE_WRITER_H + +#ifdef __cplusplus + extern "C" { +#endif + +int wave_open( long sample_rate, const char* filename ); +void wave_enable_stereo( void ); +void wave_write( short const* in, long count ); +long wave_sample_count( void ); +void wave_close( void ); + +#ifdef __cplusplus + } +#endif + +#endif |