aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorWohlstand <admin@wohlnet.ru>2017-10-18 03:03:49 +0300
committerWohlstand <admin@wohlnet.ru>2017-10-18 03:03:49 +0300
commitbb3fc091e0a5b9d1faa9198f3a72d1d332ddc85f (patch)
treef045915520ff7785a7f8c4f583de6a2a279e1a1d /src
parent380d08e1a234efb17cf15a6b6c2d00c52e4fc648 (diff)
downloadlibADLMIDI-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.cpp5
-rw-r--r--src/adlmidi.h2
-rw-r--r--src/adlmidi_midiplay.cpp8
-rw-r--r--src/midiplay/Makefile12
-rw-r--r--src/midiplay/adlmidiplay.cpp144
-rwxr-xr-xsrc/midiplay/wave_writer.c170
-rwxr-xr-xsrc/midiplay/wave_writer.h21
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