From 0e49605aaae01722a618dfdc64a328cc0e92bc04 Mon Sep 17 00:00:00 2001 From: Nils Wallménius Date: Mon, 24 Sep 2007 15:57:32 +0000 Subject: Move all of midiplay into its subdir and add a Makefile for it, add header files as necessary. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@14841 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/SOURCES | 1 - apps/plugins/SUBDIRS | 1 + apps/plugins/midi/Makefile | 74 +++++++++ apps/plugins/midi/SOURCES | 6 + apps/plugins/midi/guspat.c | 9 +- apps/plugins/midi/guspat.h | 1 + apps/plugins/midi/midifile.c | 7 +- apps/plugins/midi/midifile.h | 21 +++ apps/plugins/midi/midiplay.c | 318 ++++++++++++++++++++++++++++++++++++++ apps/plugins/midi/midiutil.c | 118 +------------- apps/plugins/midi/midiutil.h | 172 +++++++++++++++++++++ apps/plugins/midi/sequencer.c | 8 +- apps/plugins/midi/sequencer.h | 23 +++ apps/plugins/midi/synth.c | 38 +---- apps/plugins/midi/synth.h | 50 ++++++ apps/plugins/midiplay.c | 347 ------------------------------------------ 16 files changed, 688 insertions(+), 506 deletions(-) create mode 100644 apps/plugins/midi/Makefile create mode 100644 apps/plugins/midi/SOURCES create mode 100644 apps/plugins/midi/midifile.h create mode 100644 apps/plugins/midi/midiplay.c create mode 100644 apps/plugins/midi/midiutil.h create mode 100644 apps/plugins/midi/sequencer.h create mode 100644 apps/plugins/midi/synth.h delete mode 100644 apps/plugins/midiplay.c diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index 8479cd8b9b..0c615ef363 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES @@ -122,7 +122,6 @@ nim.c #if CONFIG_CODEC == SWCODEC /* software codec platforms */ mp3_encoder.c -midiplay.c wav2wv.c #else /* hardware codec platforms */ #ifndef HAVE_MMC /* not for Ondio, has no remote control pin */ diff --git a/apps/plugins/SUBDIRS b/apps/plugins/SUBDIRS index f537fb8965..5047d617ff 100644 --- a/apps/plugins/SUBDIRS +++ b/apps/plugins/SUBDIRS @@ -42,6 +42,7 @@ doom /* For all the swcodec targets */ #if CONFIG_CODEC == SWCODEC +midi mpegplayer #endif diff --git a/apps/plugins/midi/Makefile b/apps/plugins/midi/Makefile new file mode 100644 index 0000000000..0d81c87b4b --- /dev/null +++ b/apps/plugins/midi/Makefile @@ -0,0 +1,74 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id $ +# + +INCLUDES = -I$(APPSDIR) -I.. -I. $(TARGET_INC) -I$(FIRMDIR)/include -I$(FIRMDIR)/export \ + -I$(FIRMDIR)/common -I$(FIRMDIR)/drivers -I$(OUTDIR) -I$(BUILDDIR) +CFLAGS = $(INCLUDES) $(GCCOPTS) $(TARGET) $(EXTRA_DEFINES) \ + -DTARGET_ID=$(TARGET_ID) -DMEM=${MEMORYSIZE} -DPLUGIN + +ifdef APPEXTRA + INCLUDES += $(patsubst %,-I$(APPSDIR)/%,$(subst :, ,$(APPEXTRA))) +endif + +LINKFILE := $(OBJDIR)/link.lds +DEPFILE = $(OBJDIR)/dep-midiplay + +# This sets up 'SRC' based on the files mentioned in SOURCES +include $(TOOLSDIR)/makesrc.inc + +SOURCES = $(SRC) +OBJS := $(SRC:%.c=$(OBJDIR)/%.o) +DIRS = . + +ifndef SIMVER + LDS := ../plugin.lds + OUTPUT = $(OUTDIR)/midiplay.rock +else ## simulators + OUTPUT = $(OUTDIR)/midiplay.rock +endif + +all: $(OUTPUT) + +ifndef SIMVER +$(OBJDIR)/midiplay.elf: $(OBJS) $(LINKFILE) $(BITMAPLIBS) + $(call PRINTS,LD $(@F))$(CC) $(CFLAGS) -o $@ $(OBJS) -L$(BUILDDIR) -lplugin -lgcc \ + $(LINKBITMAPS) -T$(LINKFILE) -Wl,-Map,$(OBJDIR)/midiplay.map + +$(OUTPUT): $(OBJDIR)/midiplay.elf + $(call PRINTS,OBJCOPY $(@F))$(OC) -O binary $< $@ +else + +################################################### +# This is the SDL simulator version + +$(OUTPUT): $(OBJS) + $(call PRINTS,LD $(@F))$(CC) $(CFLAGS) $(SHARED_FLAG) $(OBJS) -L$(BUILDDIR) -lplugin $(LINKBITMAPS) -o $@ +ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) +# 'x' must be kept or you'll have "Win32 error 5" +# $ fgrep 5 /usr/include/w32api/winerror.h | head -1 +# #define ERROR_ACCESS_DENIED 5L +else + @chmod -x $@ +endif + +endif # end of simulator section + +include $(TOOLSDIR)/make.inc + +# MEMORYSIZE should be passed on to this makefile with the chosen memory size +# given in number of MB +$(LINKFILE): $(LDS) + $(call PRINTS,build $(@F))cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) \ + $(DEFINES) -E -P - >$@ + +clean: + $(call PRINTS,cleaning midiplay)rm -rf $(OBJDIR)/midiplay + $(SILENT)rm -f $(OBJDIR)/midiplay.* $(DEPFILE) + +-include $(DEPFILE) diff --git a/apps/plugins/midi/SOURCES b/apps/plugins/midi/SOURCES new file mode 100644 index 0000000000..74c0bf1396 --- /dev/null +++ b/apps/plugins/midi/SOURCES @@ -0,0 +1,6 @@ +midifile.c +midiutil.c +sequencer.c +guspat.c +synth.c +midiplay.c diff --git a/apps/plugins/midi/guspat.c b/apps/plugins/midi/guspat.c index 2168766eab..f44e542e2d 100644 --- a/apps/plugins/midi/guspat.c +++ b/apps/plugins/midi/guspat.c @@ -5,6 +5,7 @@ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ + * $Id$ * * Copyright (C) 2005 Stepan Moskovchenko * @@ -15,7 +16,9 @@ * KIND, either express or implied. * ****************************************************************************/ - +#include "plugin.h" +#include "guspat.h" +#include "midiutil.h" extern struct plugin_api * rb; @@ -119,8 +122,6 @@ struct GWaveform * loadWaveform(int file) return wav; } - - int selectWaveform(struct GPatch * pat, int midiNote) { /* We divide by 100 here because everyone's freq formula is slightly different */ @@ -137,7 +138,6 @@ int selectWaveform(struct GPatch * pat, int midiNote) return 0; } - struct GPatch * gusload(char * filename) { struct GPatch * gp = (struct GPatch *)malloc(sizeof(struct GPatch)); @@ -196,3 +196,4 @@ struct GPatch * gusload(char * filename) return gp; } + diff --git a/apps/plugins/midi/guspat.h b/apps/plugins/midi/guspat.h index e35f54b57a..3f858cd909 100644 --- a/apps/plugins/midi/guspat.h +++ b/apps/plugins/midi/guspat.h @@ -5,6 +5,7 @@ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ + * $Id$ * * Copyright (C) 2005 Stepan Moskovchenko * diff --git a/apps/plugins/midi/midifile.c b/apps/plugins/midi/midifile.c index 7161818421..1fa648ff50 100644 --- a/apps/plugins/midi/midifile.c +++ b/apps/plugins/midi/midifile.c @@ -5,6 +5,7 @@ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ + * $Id$ * * Copyright (C) 2005 Stepan Moskovchenko * @@ -15,8 +16,8 @@ * KIND, either express or implied. * ****************************************************************************/ - - +#include "plugin.h" +#include "midiutil.h" extern struct plugin_api * rb; @@ -234,7 +235,6 @@ struct Track * readTrack(int file) return trk; } - int readID(int file) { char id[5]; @@ -318,4 +318,3 @@ void unloadFile(struct MIDIfile * mf) } */ - diff --git a/apps/plugins/midi/midifile.h b/apps/plugins/midi/midifile.h new file mode 100644 index 0000000000..a1024d500b --- /dev/null +++ b/apps/plugins/midi/midifile.h @@ -0,0 +1,21 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 Stepan Moskovchenko + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +struct MIDIfile * loadFile(char * filename); + diff --git a/apps/plugins/midi/midiplay.c b/apps/plugins/midi/midiplay.c new file mode 100644 index 0000000000..7a1176b1c9 --- /dev/null +++ b/apps/plugins/midi/midiplay.c @@ -0,0 +1,318 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 Karl Kurbjun based on midi2wav by Stepan Moskovchenko + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "plugin.h" +#include "guspat.h" +#include "midiutil.h" +#include "synth.h" +#include "sequencer.h" +#include "midifile.h" + +PLUGIN_HEADER +PLUGIN_IRAM_DECLARE + +/* variable button definitions */ +#if CONFIG_KEYPAD == RECORDER_PAD +#define BTN_QUIT BUTTON_OFF +#define BTN_RIGHT BUTTON_RIGHT +#define BTN_UP BUTTON_UP +#define BTN_DOWN BUTTON_DOWN + +#elif CONFIG_KEYPAD == ONDIO_PAD +#define BTN_QUIT BUTTON_OFF +#define BTN_RIGHT BUTTON_RIGHT +#define BTN_UP BUTTON_UP +#define BTN_DOWN BUTTON_DOWN + +#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) +#define BTN_QUIT BUTTON_OFF +#define BTN_RIGHT BUTTON_RIGHT +#define BTN_UP BUTTON_UP +#define BTN_DOWN BUTTON_DOWN + +#define BTN_RC_QUIT BUTTON_RC_STOP + +#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ + (CONFIG_KEYPAD == IPOD_1G2G_PAD) +#define BTN_QUIT (BUTTON_SELECT | BUTTON_MENU) +#define BTN_RIGHT BUTTON_RIGHT +#define BTN_UP BUTTON_SCROLL_FWD +#define BTN_DOWN BUTTON_SCROLL_BACK + +#elif (CONFIG_KEYPAD == GIGABEAT_PAD) +#define BTN_QUIT BUTTON_POWER +#define BTN_RIGHT BUTTON_RIGHT +#define BTN_UP BUTTON_UP +#define BTN_DOWN BUTTON_DOWN + +#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \ +(CONFIG_KEYPAD == SANSA_C200_PAD) +#define BTN_QUIT BUTTON_POWER +#define BTN_RIGHT BUTTON_RIGHT +#define BTN_UP BUTTON_UP +#define BTN_DOWN BUTTON_DOWN + +#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD +#define BTN_QUIT BUTTON_POWER +#define BTN_RIGHT BUTTON_RIGHT +#define BTN_UP BUTTON_UP +#define BTN_DOWN BUTTON_DOWN + +#elif CONFIG_KEYPAD == IRIVER_H10_PAD +#define BTN_QUIT BUTTON_POWER +#define BTN_RIGHT BUTTON_RIGHT +#define BTN_UP BUTTON_SCROLL_UP +#define BTN_DOWN BUTTON_SCROLL_DOWN + +#endif + +#undef SYNC + +#ifdef SIMULATOR + #define SYNC +#endif + +struct MIDIfile * mf IBSS_ATTR; + +int numberOfSamples IBSS_ATTR; +long bpm IBSS_ATTR; + +long gmbuf[BUF_SIZE*NBUF]; + +int quit=0; +struct plugin_api * rb; + +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) +{ + int retval = 0; + + PLUGIN_IRAM_INIT(api) + + rb = api; + if(parameter == NULL) + { + rb->splash(HZ*2, " Play .MID file "); + return PLUGIN_OK; + } + rb->lcd_setfont(0); + +#if defined(HAVE_ADJUSTABLE_CPU_FREQ) + rb->cpu_boost(true); +#endif + + printf("%s", parameter); + /* rb->splash(HZ, true, parameter); */ + +#ifdef RB_PROFILE + rb->profile_thread(); +#endif + + retval = midimain(parameter); + +#ifdef RB_PROFILE + rb->profstop(); +#endif + + rb->pcm_play_stop(); + rb->pcm_set_frequency(HW_SAMPR_DEFAULT); + +#if defined(HAVE_ADJUSTABLE_CPU_FREQ) + rb->cpu_boost(false); +#endif + + rb->splash(HZ, "FINISHED PLAYING"); + + if(retval == -1) + return PLUGIN_ERROR; + return PLUGIN_OK; +} + +bool swap=0; +bool lastswap=1; + +inline void synthbuf(void) +{ + long *outptr; + register int i; + static int currentSample=0; + int synthtemp[2]; + +#ifndef SYNC + if(lastswap==swap) return; + lastswap=swap; + + outptr=(swap ? gmbuf : gmbuf+BUF_SIZE); +#else + outptr=gmbuf; +#endif + + for(i=0; ipcm_play_stop(); +#if INPUT_SRC_CAPS != 0 + /* Select playback */ + rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); + rb->audio_set_output_source(AUDIO_SRC_PLAYBACK); +#endif + rb->pcm_set_frequency(SAMPLE_RATE); // 44100 22050 11025 +//#endif + + /* + * tick() will do one MIDI clock tick. Then, there's a loop here that + * will generate the right number of samples per MIDI tick. The whole + * MIDI playback is timed in terms of this value.. there are no forced + * delays or anything. It just produces enough samples for each tick, and + * the playback of these samples is what makes the timings right. + * + * This seems to work quite well. On a laptop, anyway. + */ + + printf("Okay, starting sequencing"); + + bpm=mf->div*1000000/tempo; + numberOfSamples=SAMPLE_RATE/bpm; + + + + /* Skip over any junk in the beginning of the file, so start playing */ + /* after the first note event */ + do + { + notesUsed = 0; + for(a=0; apcm_play_data(&get_more, NULL, 0); +//#endif + + int vol=0; + + while(!quit) + { + #ifndef SYNC + synthbuf(); + #endif + rb->yield(); + + /* Prevent idle poweroff */ + rb->reset_poweroff_timer(); + + /* Code taken from Oscilloscope plugin */ + switch(rb->button_get(false)) + { + case BTN_UP: + case BTN_UP | BUTTON_REPEAT: + vol = rb->global_settings->volume; + if (vol < rb->sound_max(SOUND_VOLUME)) + { + vol++; + rb->sound_set(SOUND_VOLUME, vol); + rb->global_settings->volume = vol; + } + break; + + case BTN_DOWN: + case BTN_DOWN | BUTTON_REPEAT: + vol = rb->global_settings->volume; + if (vol > rb->sound_min(SOUND_VOLUME)) + { + vol--; + rb->sound_set(SOUND_VOLUME, vol); + rb->global_settings->volume = vol; + } + break; + + case BTN_RIGHT: + { + /* Skip 3 seconds */ + /* Should skip length be retrieved from the RB settings? */ + int samp = 3*SAMPLE_RATE; + int tickCount = samp / numberOfSamples; + int a=0; + for(a=0; a ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ + * $Id$ * * Copyright (C) 2005 Stepan Moskovchenko * @@ -15,134 +16,23 @@ * KIND, either express or implied. * ****************************************************************************/ - - -#define BYTE unsigned char - -//Data chunk ID types, returned by readID() -#define ID_UNKNOWN -1 -#define ID_MTHD 1 -#define ID_MTRK 2 -#define ID_EOF 3 -#define ID_RIFF 4 - - -//MIDI Commands -#define MIDI_NOTE_OFF 128 -#define MIDI_NOTE_ON 144 -#define MIDI_AFTERTOUCH 160 -#define MIDI_CONTROL 176 -#define MIDI_PRGM 192 -#define MIDI_PITCHW 224 - - -//MIDI Controllers -#define CTRL_VOLUME 7 -#define CTRL_BALANCE 8 -#define CTRL_PANNING 10 -#define CHANNEL 1 - -//Most of these are deprecated.. rampdown is used, maybe one other one too -#define STATE_ATTACK 1 -#define STATE_DECAY 2 -#define STATE_SUSTAIN 3 -#define STATE_RELEASE 4 -#define STATE_RAMPDOWN 5 - -//Loop states -#define STATE_LOOPING 7 -#define STATE_NONLOOPING 8 - -//Various bits in the GUS mode byte -#define LOOP_ENABLED 4 -#define LOOP_PINGPONG 8 -#define LOOP_REVERSE 16 - -#define LOOPDIR_FORWARD 0 -#define LOOPDIR_REVERSE 1 - +#include "plugin.h" +#include "midiutil.h" extern struct plugin_api * rb; -int printf(const char *fmt, ...); - int chVol[16] IBSS_ATTR; /* Channel volume */ int chPanLeft[16] IBSS_ATTR; /* Channel panning */ int chPanRight[16] IBSS_ATTR; int chPat[16] IBSS_ATTR; /* Channel patch */ int chPW[16] IBSS_ATTR; /* Channel pitch wheel, MSB only */ - struct GPatch * gusload(char *); struct GPatch * patchSet[128]; struct GPatch * drumSet[128]; -struct Event -{ - unsigned int delta; - unsigned char status, d1, d2; - unsigned int len; - unsigned char * evData; -}; - -struct Track -{ - unsigned int size; - unsigned int numEvents; - unsigned int delta; /* For sequencing */ - unsigned int pos; /* For sequencing */ - void * dataBlock; -}; - - -struct MIDIfile -{ - int Length; - unsigned short numTracks; - unsigned short div; /* Time division, X ticks per millisecond */ - struct Track * tracks[48]; - unsigned char patches[128]; - int numPatches; -}; - -/* -struct SynthObject -{ - struct GWaveform * wf; - unsigned int delta; - unsigned int decay; - unsigned int cp; - unsigned char state, loopState, loopDir; - unsigned char note, vol, ch, isUsed; - int curRate, curOffset, targetOffset; - unsigned int curPoint; -}; -*/ - -struct SynthObject -{ - struct GWaveform * wf; - int delta; - int decay; - unsigned int cp; /* unsigned int */ - int state, loopState, loopDir; - int note, vol, ch, isUsed; - int curRate, curOffset, targetOffset; - int curPoint; - signed short int volscale; -}; - struct SynthObject voices[MAX_VOICES] IBSS_ATTR; -void sendEvent(struct Event * ev); -inline void setPoint(struct SynthObject * so, int pt); -struct Event * getEvent(struct Track * tr, int evNum); -int readTwoBytes(int file); -int readFourBytes(int file); -int readVarData(int file); -int midimain(void * filename); - - void *alloc(int size) { static char *offset = NULL; @@ -180,7 +70,6 @@ void *alloc(int size) return ret; } - /* Rick's code */ /* void *alloc(int size) @@ -267,3 +156,4 @@ void exit(int code) { code = code; /* Stub function, kill warning for now */ } + diff --git a/apps/plugins/midi/midiutil.h b/apps/plugins/midi/midiutil.h new file mode 100644 index 0000000000..cfaa4fb2fe --- /dev/null +++ b/apps/plugins/midi/midiutil.h @@ -0,0 +1,172 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 Stepan Moskovchenko + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#define FRACTSIZE 10 + +#define BUF_SIZE 256 +#define NBUF 2 + + +#ifndef SIMULATOR + +#if (HW_SAMPR_CAPS & SAMPR_CAP_22) +#define SAMPLE_RATE SAMPR_22 // 44100 22050 11025 +#else +#define SAMPLE_RATE SAMPR_44 // 44100 22050 11025 +#endif + +#define MAX_VOICES 20 // Note: 24 midi channels is the minimum general midi + // spec implementation + +#else // Simulator requires 44100, and we can afford to use more voices + +#define SAMPLE_RATE SAMPR_44 +#define MAX_VOICES 48 + +#endif + +#define BYTE unsigned char + +//Data chunk ID types, returned by readID() +#define ID_UNKNOWN -1 +#define ID_MTHD 1 +#define ID_MTRK 2 +#define ID_EOF 3 +#define ID_RIFF 4 + +//MIDI Commands +#define MIDI_NOTE_OFF 128 +#define MIDI_NOTE_ON 144 +#define MIDI_AFTERTOUCH 160 +#define MIDI_CONTROL 176 +#define MIDI_PRGM 192 +#define MIDI_PITCHW 224 + +//MIDI Controllers +#define CTRL_VOLUME 7 +#define CTRL_BALANCE 8 +#define CTRL_PANNING 10 +#define CHANNEL 1 + +//Most of these are deprecated.. rampdown is used, maybe one other one too +#define STATE_ATTACK 1 +#define STATE_DECAY 2 +#define STATE_SUSTAIN 3 +#define STATE_RELEASE 4 +#define STATE_RAMPDOWN 5 + +//Loop states +#define STATE_LOOPING 7 +#define STATE_NONLOOPING 8 + +//Various bits in the GUS mode byte +#define LOOP_ENABLED 4 +#define LOOP_PINGPONG 8 +#define LOOP_REVERSE 16 + +#define LOOPDIR_FORWARD 0 +#define LOOPDIR_REVERSE 1 + +struct MIDIfile +{ + int Length; + unsigned short numTracks; + unsigned short div; /* Time division, X ticks per millisecond */ + struct Track * tracks[48]; + unsigned char patches[128]; + int numPatches; +}; + +/* +struct SynthObject +{ + struct GWaveform * wf; + unsigned int delta; + unsigned int decay; + unsigned int cp; + unsigned char state, loopState, loopDir; + unsigned char note, vol, ch, isUsed; + int curRate, curOffset, targetOffset; + unsigned int curPoint; +}; +*/ + +struct SynthObject +{ + struct GWaveform * wf; + int delta; + int decay; + unsigned int cp; /* unsigned int */ + int state, loopState, loopDir; + int note, vol, ch, isUsed; + int curRate, curOffset, targetOffset; + int curPoint; + signed short int volscale; +}; + +struct Event +{ + unsigned int delta; + unsigned char status, d1, d2; + unsigned int len; + unsigned char * evData; +}; + +struct Track +{ + unsigned int size; + unsigned int numEvents; + unsigned int delta; /* For sequencing */ + unsigned int pos; /* For sequencing */ + void * dataBlock; +}; + +int printf(const char *fmt, ...); +int midimain(void * filename); +unsigned char readChar(int file); +void sendEvent(struct Event * ev); +inline void setPoint(struct SynthObject * so, int pt); +struct Event * getEvent(struct Track * tr, int evNum); +int readTwoBytes(int file); +int readFourBytes(int file); +int readVarData(int file); +int eof(int fd); +unsigned char * readData(int file, int len); +void exit(int code); + +#define malloc(n) my_malloc(n) +void * my_malloc(int size); + +extern struct SynthObject voices[MAX_VOICES]; + +extern int chVol[16]; /* Channel volume */ +extern int chPanLeft[16]; /* Channel panning */ +extern int chPanRight[16]; +extern int chPat[16]; /* Channel patch */ +extern int chPW[16]; /* Channel pitch wheel, MSB only */ + +extern struct GPatch * gusload(char *); +extern struct GPatch * patchSet[128]; +extern struct GPatch * drumSet[128]; + +extern struct MIDIfile * mf; + +extern int numberOfSamples; +extern long bpm; + diff --git a/apps/plugins/midi/sequencer.c b/apps/plugins/midi/sequencer.c index 68c29f35ad..473b7e4e2c 100644 --- a/apps/plugins/midi/sequencer.c +++ b/apps/plugins/midi/sequencer.c @@ -5,6 +5,7 @@ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ + * $Id$ * * Copyright (C) 2005 Stepan Moskovchenko * @@ -15,6 +16,9 @@ * KIND, either express or implied. * ****************************************************************************/ +#include "plugin.h" +#include "midiutil.h" +#include "guspat.h" void setVolScale(int a); @@ -22,7 +26,6 @@ extern struct plugin_api * rb; long tempo=375000; - inline void setVol(int ch, int vol) { int a=0; @@ -119,7 +122,6 @@ long pitchTbl[] ICONST_ATTR={ 73297,73330,73363,73396,73429,73462,73495,73528 }; - void findDelta(struct SynthObject * so, int ch, int note) { @@ -147,7 +149,6 @@ inline void setPW(int ch, int msb, int lsb) } } - /* Sets the volume scaling by channel volume and note volume */ /* This way we can do the multiplication/indexing once per */ /* MIDI event at the most, instead of once per sample. */ @@ -375,3 +376,4 @@ int tick(void) else return 0; } + diff --git a/apps/plugins/midi/sequencer.h b/apps/plugins/midi/sequencer.h new file mode 100644 index 0000000000..cfa81f99c6 --- /dev/null +++ b/apps/plugins/midi/sequencer.h @@ -0,0 +1,23 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 Stepan Moskovchenko + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +int tick(void); + +extern long tempo; + diff --git a/apps/plugins/midi/synth.c b/apps/plugins/midi/synth.c index 00a01e41cb..917a8ae13d 100644 --- a/apps/plugins/midi/synth.c +++ b/apps/plugins/midi/synth.c @@ -5,6 +5,7 @@ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ + * $Id$ * * Copyright (C) 2005 Stepan Moskovchenko * @@ -15,6 +16,10 @@ * KIND, either express or implied. * ****************************************************************************/ +#include "plugin.h" +#include "guspat.h" +#include "midiutil.h" +#include "synth.h" extern struct plugin_api * rb; @@ -43,8 +48,6 @@ void readTextBlock(int file, char * buf) rb->lseek(file, -1, SEEK_CUR); } - - /* Filename is the name of the config file */ /* The MIDI file should have been loaded at this point */ int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig) @@ -400,34 +403,3 @@ signed short int synthVoice(struct SynthObject * so) return s*so->volscale>>14; } - - - - -inline void synthSample(int * mixL, int * mixR) -{ - register int dL=0; - register int dR=0; - register short sample=0; - register struct SynthObject *voicept=voices; - struct SynthObject *lastvoice=&voices[MAX_VOICES]; - - while(voicept!=lastvoice) - { - if(voicept->isUsed==1) - { - sample = synthVoice(voicept); - dL += (sample*chPanLeft[voicept->ch])>>7; - dR += (sample*chPanRight[voicept->ch])>>7; - } - voicept++; - } - - *mixL=dL; - *mixR=dR; - - /* TODO: Automatic Gain Control, anyone? */ - /* Or, should this be implemented on the DSP's output volume instead? */ - - return; /* No more ghetto lowpass filter.. linear intrpolation works well. */ -} diff --git a/apps/plugins/midi/synth.h b/apps/plugins/midi/synth.h new file mode 100644 index 0000000000..daaf26d5f6 --- /dev/null +++ b/apps/plugins/midi/synth.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 Stepan Moskovchenko + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig); +signed short int synthVoice(struct SynthObject * so); + +static inline void synthSample(int * mixL, int * mixR) +{ + register int dL=0; + register int dR=0; + register short sample=0; + register struct SynthObject *voicept=voices; + struct SynthObject *lastvoice=&voices[MAX_VOICES]; + + while(voicept!=lastvoice) + { + if(voicept->isUsed==1) + { + sample = synthVoice(voicept); + dL += (sample*chPanLeft[voicept->ch])>>7; + dR += (sample*chPanRight[voicept->ch])>>7; + } + voicept++; + } + + *mixL=dL; + *mixR=dR; + + /* TODO: Automatic Gain Control, anyone? */ + /* Or, should this be implemented on the DSP's output volume instead? */ + + return; /* No more ghetto lowpass filter.. linear intrpolation works well. */ +} + diff --git a/apps/plugins/midiplay.c b/apps/plugins/midiplay.c deleted file mode 100644 index f8a6929661..0000000000 --- a/apps/plugins/midiplay.c +++ /dev/null @@ -1,347 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * - * Copyright (C) 2005 Karl Kurbjun based on midi2wav by Stepan Moskovchenko - * - * All files in this archive are subject to the GNU General Public License. - * See the file COPYING in the source tree root for full license agreement. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#include "../../plugin.h" - -PLUGIN_HEADER -PLUGIN_IRAM_DECLARE - -/* variable button definitions */ -#if CONFIG_KEYPAD == RECORDER_PAD -#define BTN_QUIT BUTTON_OFF -#define BTN_RIGHT BUTTON_RIGHT -#define BTN_UP BUTTON_UP -#define BTN_DOWN BUTTON_DOWN - -#elif CONFIG_KEYPAD == ONDIO_PAD -#define BTN_QUIT BUTTON_OFF -#define BTN_RIGHT BUTTON_RIGHT -#define BTN_UP BUTTON_UP -#define BTN_DOWN BUTTON_DOWN - -#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) -#define BTN_QUIT BUTTON_OFF -#define BTN_RIGHT BUTTON_RIGHT -#define BTN_UP BUTTON_UP -#define BTN_DOWN BUTTON_DOWN - -#define BTN_RC_QUIT BUTTON_RC_STOP - -#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ - (CONFIG_KEYPAD == IPOD_1G2G_PAD) -#define BTN_QUIT (BUTTON_SELECT | BUTTON_MENU) -#define BTN_RIGHT BUTTON_RIGHT -#define BTN_UP BUTTON_SCROLL_FWD -#define BTN_DOWN BUTTON_SCROLL_BACK - -#elif (CONFIG_KEYPAD == GIGABEAT_PAD) -#define BTN_QUIT BUTTON_POWER -#define BTN_RIGHT BUTTON_RIGHT -#define BTN_UP BUTTON_UP -#define BTN_DOWN BUTTON_DOWN - -#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \ -(CONFIG_KEYPAD == SANSA_C200_PAD) -#define BTN_QUIT BUTTON_POWER -#define BTN_RIGHT BUTTON_RIGHT -#define BTN_UP BUTTON_UP -#define BTN_DOWN BUTTON_DOWN - - -#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD -#define BTN_QUIT BUTTON_POWER -#define BTN_RIGHT BUTTON_RIGHT -#define BTN_UP BUTTON_UP -#define BTN_DOWN BUTTON_DOWN - -#elif CONFIG_KEYPAD == IRIVER_H10_PAD -#define BTN_QUIT BUTTON_POWER -#define BTN_RIGHT BUTTON_RIGHT -#define BTN_UP BUTTON_SCROLL_UP -#define BTN_DOWN BUTTON_SCROLL_DOWN - -#endif - - - -#define FRACTSIZE 10 - -#ifndef SIMULATOR - -#if (HW_SAMPR_CAPS & SAMPR_CAP_22) -#define SAMPLE_RATE SAMPR_22 // 44100 22050 11025 -#else -#define SAMPLE_RATE SAMPR_44 // 44100 22050 11025 -#endif - -#define MAX_VOICES 20 // Note: 24 midi channels is the minimum general midi - // spec implementation - -#else // Simulator requires 44100, and we can afford to use more voices - -#define SAMPLE_RATE SAMPR_44 -#define MAX_VOICES 48 - -#endif - - -#define BUF_SIZE 256 -#define NBUF 2 - -#undef SYNC - -#ifdef SIMULATOR - #define SYNC -#endif - -struct MIDIfile * mf IBSS_ATTR; - -int numberOfSamples IBSS_ATTR; -long bpm IBSS_ATTR; - -#include "midi/midiutil.c" -#include "midi/guspat.h" -#include "midi/guspat.c" -#include "midi/sequencer.c" -#include "midi/midifile.c" -#include "midi/synth.c" - -long gmbuf[BUF_SIZE*NBUF]; - -int quit=0; -struct plugin_api * rb; - -enum plugin_status plugin_start(struct plugin_api* api, void* parameter) -{ - int retval = 0; - - PLUGIN_IRAM_INIT(api) - - rb = api; - if(parameter == NULL) - { - rb->splash(HZ*2, " Play .MID file "); - return PLUGIN_OK; - } - rb->lcd_setfont(0); - -#if defined(HAVE_ADJUSTABLE_CPU_FREQ) - rb->cpu_boost(true); -#endif - - printf("%s", parameter); - /* rb->splash(HZ, true, parameter); */ - -#ifdef RB_PROFILE - rb->profile_thread(); -#endif - - retval = midimain(parameter); - -#ifdef RB_PROFILE - rb->profstop(); -#endif - - rb->pcm_play_stop(); - rb->pcm_set_frequency(HW_SAMPR_DEFAULT); - -#if defined(HAVE_ADJUSTABLE_CPU_FREQ) - rb->cpu_boost(false); -#endif - - rb->splash(HZ, "FINISHED PLAYING"); - - if(retval == -1) - return PLUGIN_ERROR; - return PLUGIN_OK; -} - -bool swap=0; -bool lastswap=1; - -inline void synthbuf(void) -{ - long *outptr; - register int i; - static int currentSample=0; - int synthtemp[2]; - -#ifndef SYNC - if(lastswap==swap) return; - lastswap=swap; - - outptr=(swap ? gmbuf : gmbuf+BUF_SIZE); -#else - outptr=gmbuf; -#endif - - for(i=0; ipcm_play_stop(); -#if INPUT_SRC_CAPS != 0 - /* Select playback */ - rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); - rb->audio_set_output_source(AUDIO_SRC_PLAYBACK); -#endif - rb->pcm_set_frequency(SAMPLE_RATE); // 44100 22050 11025 -//#endif - - /* - * tick() will do one MIDI clock tick. Then, there's a loop here that - * will generate the right number of samples per MIDI tick. The whole - * MIDI playback is timed in terms of this value.. there are no forced - * delays or anything. It just produces enough samples for each tick, and - * the playback of these samples is what makes the timings right. - * - * This seems to work quite well. On a laptop, anyway. - */ - - printf("Okay, starting sequencing"); - - bpm=mf->div*1000000/tempo; - numberOfSamples=SAMPLE_RATE/bpm; - - - - /* Skip over any junk in the beginning of the file, so start playing */ - /* after the first note event */ - do - { - notesUsed = 0; - for(a=0; apcm_play_data(&get_more, NULL, 0); -//#endif - - int vol=0; - - while(!quit) - { - #ifndef SYNC - synthbuf(); - #endif - rb->yield(); - - /* Prevent idle poweroff */ - rb->reset_poweroff_timer(); - - /* Code taken from Oscilloscope plugin */ - switch(rb->button_get(false)) - { - case BTN_UP: - case BTN_UP | BUTTON_REPEAT: - vol = rb->global_settings->volume; - if (vol < rb->sound_max(SOUND_VOLUME)) - { - vol++; - rb->sound_set(SOUND_VOLUME, vol); - rb->global_settings->volume = vol; - } - break; - - case BTN_DOWN: - case BTN_DOWN | BUTTON_REPEAT: - vol = rb->global_settings->volume; - if (vol > rb->sound_min(SOUND_VOLUME)) - { - vol--; - rb->sound_set(SOUND_VOLUME, vol); - rb->global_settings->volume = vol; - } - break; - - case BTN_RIGHT: - { - /* Skip 3 seconds */ - /* Should skip length be retrieved from the RB settings? */ - int samp = 3*SAMPLE_RATE; - int tickCount = samp / numberOfSamples; - int a=0; - for(a=0; a