diff options
Diffstat (limited to 'apps/plugins/midiplay.c')
-rw-r--r-- | apps/plugins/midiplay.c | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/apps/plugins/midiplay.c b/apps/plugins/midiplay.c new file mode 100644 index 0000000000..f279e72e4e --- /dev/null +++ b/apps/plugins/midiplay.c | |||
@@ -0,0 +1,217 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2005 Karl Kurbjun based on midi2wav by Stepan Moskovchenko | ||
10 | * | ||
11 | * All files in this archive are subject to the GNU General Public License. | ||
12 | * See the file COPYING in the source tree root for full license agreement. | ||
13 | * | ||
14 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
15 | * KIND, either express or implied. | ||
16 | * | ||
17 | ****************************************************************************/ | ||
18 | |||
19 | #include "../../plugin.h" | ||
20 | |||
21 | PLUGIN_HEADER | ||
22 | |||
23 | #define SAMPLE_RATE 22050 // 44100 22050 11025 | ||
24 | #define MAX_VOICES 12 // Note: 24 midi channels is the minimum general midi | ||
25 | // spec implementation | ||
26 | #define BUF_SIZE 512 | ||
27 | #define NBUF 2 | ||
28 | |||
29 | #undef SYNC | ||
30 | struct MIDIfile * mf IBSS_ATTR; | ||
31 | |||
32 | int numberOfSamples IBSS_ATTR; | ||
33 | long bpm IBSS_ATTR; | ||
34 | |||
35 | #include "midi/midiutil.c" | ||
36 | #include "midi/guspat.h" | ||
37 | #include "midi/guspat.c" | ||
38 | #include "midi/sequencer.c" | ||
39 | #include "midi/midifile.c" | ||
40 | #include "midi/synth.c" | ||
41 | |||
42 | short gmbuf[BUF_SIZE*NBUF] IBSS_ATTR; | ||
43 | |||
44 | int quit=0; | ||
45 | struct plugin_api * rb; | ||
46 | |||
47 | #ifdef USE_IRAM | ||
48 | extern char iramcopy[]; | ||
49 | extern char iramstart[]; | ||
50 | extern char iramend[]; | ||
51 | extern char iedata[]; | ||
52 | extern char iend[]; | ||
53 | #endif | ||
54 | |||
55 | enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | ||
56 | { | ||
57 | rb = api; | ||
58 | |||
59 | if(parameter == NULL) | ||
60 | { | ||
61 | rb->splash(HZ*2, true, " Play .MID file "); | ||
62 | return PLUGIN_OK; | ||
63 | } | ||
64 | rb->lcd_setfont(0); | ||
65 | |||
66 | #ifdef USE_IRAM | ||
67 | rb->memcpy(iramstart, iramcopy, iramend-iramstart); | ||
68 | rb->memset(iedata, 0, iend - iedata); | ||
69 | #endif | ||
70 | |||
71 | #if !defined(SIMULATOR) && defined(HAVE_ADJUSTABLE_CPU_FREQ) | ||
72 | rb->cpu_boost(true); | ||
73 | #endif | ||
74 | |||
75 | printf("\n%s", parameter); | ||
76 | /* rb->splash(HZ, true, parameter); */ | ||
77 | |||
78 | #ifdef RB_PROFILE | ||
79 | rb->profile_thread(); | ||
80 | #endif | ||
81 | |||
82 | if(midimain(parameter) == -1) | ||
83 | return PLUGIN_ERROR; | ||
84 | |||
85 | #ifdef RB_PROFILE | ||
86 | rb->profstop(); | ||
87 | #endif | ||
88 | |||
89 | #ifndef SIMULATOR | ||
90 | rb->pcm_play_stop(); | ||
91 | rb->pcm_set_frequency(44100); // 44100 | ||
92 | #endif | ||
93 | |||
94 | #if !defined(SIMULATOR) && defined(HAVE_ADJUSTABLE_CPU_FREQ) | ||
95 | rb->cpu_boost(false); | ||
96 | #endif | ||
97 | |||
98 | rb->splash(HZ, true, "FINISHED PLAYING"); | ||
99 | |||
100 | return PLUGIN_OK; | ||
101 | } | ||
102 | |||
103 | bool swap=0; | ||
104 | bool lastswap=1; | ||
105 | |||
106 | inline void synthbuf(void) | ||
107 | { | ||
108 | short *outptr; | ||
109 | register int i; | ||
110 | static int currentSample=0; | ||
111 | int synthtemp[2]; | ||
112 | |||
113 | #ifndef SYNC | ||
114 | if(lastswap==swap) return; | ||
115 | lastswap=swap; | ||
116 | |||
117 | outptr=(swap ? gmbuf : gmbuf+BUF_SIZE); | ||
118 | #else | ||
119 | outptr=gmbuf; | ||
120 | #endif | ||
121 | |||
122 | for(i=0; i<BUF_SIZE/2; i++) | ||
123 | { | ||
124 | synthSample(&synthtemp[0], &synthtemp[1]); | ||
125 | currentSample++; | ||
126 | *outptr=synthtemp[0]&0xFFFF; | ||
127 | outptr++; | ||
128 | *outptr=synthtemp[1]&0xFFFF; | ||
129 | outptr++; | ||
130 | if(currentSample==numberOfSamples) | ||
131 | { | ||
132 | if( tick() == 0 ) quit=1; | ||
133 | currentSample=0; | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
138 | void get_more(unsigned char** start, size_t* size) | ||
139 | { | ||
140 | #ifndef SYNC | ||
141 | if(lastswap!=swap) | ||
142 | { | ||
143 | printf("Buffer miss!"); // Comment out the printf to make missses less noticable. | ||
144 | /* | ||
145 | int a=0; | ||
146 | for(a=0; a<MAX_VOICES; a++) | ||
147 | { | ||
148 | voices[a].isUsed=0; | ||
149 | } | ||
150 | */ | ||
151 | } | ||
152 | |||
153 | #else | ||
154 | synthbuf(); // For some reason midiplayer crashes when an update is forced | ||
155 | #endif | ||
156 | |||
157 | *size = BUF_SIZE*sizeof(short); | ||
158 | #ifndef SYNC | ||
159 | *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE)); | ||
160 | swap=!swap; | ||
161 | #else | ||
162 | *start = (unsigned char*)(gmbuf); | ||
163 | #endif | ||
164 | } | ||
165 | |||
166 | int midimain(void * filename) | ||
167 | { | ||
168 | int button; | ||
169 | |||
170 | /* rb->splash(HZ/5, true, "LOADING MIDI"); */ | ||
171 | printf("\nLoading file"); | ||
172 | mf= loadFile(filename); | ||
173 | |||
174 | /* rb->splash(HZ/5, true, "LOADING PATCHES"); */ | ||
175 | if (initSynth(mf, "/.rockbox/patchset/patchset.cfg", "/.rockbox/patchset/drums.cfg") == -1) | ||
176 | return -1; | ||
177 | |||
178 | #ifndef SIMULATOR | ||
179 | rb->pcm_play_stop(); | ||
180 | rb->pcm_set_frequency(SAMPLE_RATE); // 44100 22050 11025 | ||
181 | #endif | ||
182 | |||
183 | /* | ||
184 | * tick() will do one MIDI clock tick. Then, there's a loop here that | ||
185 | * will generate the right number of samples per MIDI tick. The whole | ||
186 | * MIDI playback is timed in terms of this value.. there are no forced | ||
187 | * delays or anything. It just produces enough samples for each tick, and | ||
188 | * the playback of these samples is what makes the timings right. | ||
189 | * | ||
190 | * This seems to work quite well. | ||
191 | */ | ||
192 | |||
193 | printf("\nOkay, starting sequencing"); | ||
194 | |||
195 | bpm=mf->div*1000000/tempo; | ||
196 | numberOfSamples=SAMPLE_RATE/bpm; | ||
197 | |||
198 | tick(); | ||
199 | |||
200 | synthbuf(); | ||
201 | #ifndef SIMULATOR | ||
202 | rb->pcm_play_data(&get_more, NULL, 0); | ||
203 | #endif | ||
204 | |||
205 | button=rb->button_status(); | ||
206 | |||
207 | while(!quit) | ||
208 | { | ||
209 | #ifndef SYNC | ||
210 | synthbuf(); | ||
211 | #endif | ||
212 | rb->yield(); | ||
213 | if(rb->button_status()!=button) quit=1; | ||
214 | } | ||
215 | |||
216 | return 0; | ||
217 | } | ||