Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
Nils Wallménius | 0e49605 | 2007-09-24 15:57:32 +0000 | [diff] [blame] | 8 | * $Id$ |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 9 | * |
| 10 | * Copyright (C) 2005 Stepan Moskovchenko |
| 11 | * |
| 12 | * All files in this archive are subject to the GNU General Public License. |
| 13 | * See the file COPYING in the source tree root for full license agreement. |
| 14 | * |
| 15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 16 | * KIND, either express or implied. |
| 17 | * |
| 18 | ****************************************************************************/ |
Nils Wallménius | 0e49605 | 2007-09-24 15:57:32 +0000 | [diff] [blame] | 19 | #include "plugin.h" |
| 20 | #include "guspat.h" |
| 21 | #include "midiutil.h" |
| 22 | #include "synth.h" |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 23 | |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 24 | extern struct plugin_api * rb; |
| 25 | |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 26 | void readTextBlock(int file, char * buf) |
| 27 | { |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 28 | char c = 0; |
| 29 | do |
| 30 | { |
| 31 | c = readChar(file); |
| 32 | } while(c == '\n' || c == ' ' || c=='\t'); |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 33 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 34 | rb->lseek(file, -1, SEEK_CUR); |
| 35 | int cp = 0; |
| 36 | do |
| 37 | { |
| 38 | c = readChar(file); |
| 39 | buf[cp] = c; |
| 40 | cp++; |
| 41 | } while (c != '\n' && c != ' ' && c != '\t' && !eof(file)); |
| 42 | buf[cp-1]=0; |
| 43 | rb->lseek(file, -1, SEEK_CUR); |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 44 | } |
| 45 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 46 | /* Filename is the name of the config file */ |
| 47 | /* The MIDI file should have been loaded at this point */ |
Stepan Moskovchenko | 5811214 | 2005-04-15 20:27:04 +0000 | [diff] [blame] | 48 | int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig) |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 49 | { |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 50 | char patchUsed[128]; |
| 51 | char drumUsed[128]; |
| 52 | int a=0; |
| 53 | for(a=0; a<MAX_VOICES; a++) |
| 54 | { |
| 55 | voices[a].cp=0; |
| 56 | voices[a].vol=0; |
| 57 | voices[a].ch=0; |
| 58 | voices[a].isUsed=0; |
| 59 | voices[a].note=0; |
| 60 | } |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 61 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 62 | for(a=0; a<16; a++) |
| 63 | { |
| 64 | chVol[a]=100; /* Default, not quite full blast.. */ |
Nils Wallménius | e1940b8 | 2007-10-04 19:36:42 +0000 | [diff] [blame] | 65 | chPan[a]=64; /* Center */ |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 66 | chPat[a]=0; /* Ac Gr Piano */ |
Nils Wallménius | e1940b8 | 2007-10-04 19:36:42 +0000 | [diff] [blame] | 67 | chPW[a]=256; /* .. not .. bent ? */ |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 68 | } |
| 69 | for(a=0; a<128; a++) |
| 70 | { |
| 71 | patchSet[a]=NULL; |
| 72 | drumSet[a]=NULL; |
| 73 | patchUsed[a]=0; |
| 74 | drumUsed[a]=0; |
| 75 | } |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 76 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 77 | /* |
| 78 | * Always load the piano. |
| 79 | * Some files will assume its loaded without specifically |
| 80 | * issuing a Patch command... then we wonder why we can't hear anything |
| 81 | */ |
| 82 | patchUsed[0]=1; |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 83 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 84 | /* Scan the file to see what needs to be loaded */ |
Stepan Moskovchenko | 8b6d287 | 2007-09-27 03:59:33 +0000 | [diff] [blame] | 85 | if(mf != NULL) |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 86 | { |
Stepan Moskovchenko | 8b6d287 | 2007-09-27 03:59:33 +0000 | [diff] [blame] | 87 | for(a=0; a<mf->numTracks; a++) |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 88 | { |
Stepan Moskovchenko | 8b6d287 | 2007-09-27 03:59:33 +0000 | [diff] [blame] | 89 | unsigned int ts=0; |
| 90 | |
| 91 | if(mf->tracks[a] == NULL) |
| 92 | { |
| 93 | printf("NULL TRACK !!!"); |
| 94 | rb->splash(HZ*2, "Null Track in loader."); |
| 95 | return -1; |
| 96 | } |
| 97 | |
| 98 | for(ts=0; ts<mf->tracks[a]->numEvents; ts++) |
| 99 | { |
| 100 | |
| 101 | if((getEvent(mf->tracks[a], ts)->status) == (MIDI_NOTE_ON+9)) |
| 102 | drumUsed[getEvent(mf->tracks[a], ts)->d1]=1; |
| 103 | |
| 104 | if( (getEvent(mf->tracks[a], ts)->status & 0xF0) == MIDI_PRGM) |
| 105 | patchUsed[getEvent(mf->tracks[a], ts)->d1]=1; |
| 106 | } |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 107 | } |
Stepan Moskovchenko | 8b6d287 | 2007-09-27 03:59:33 +0000 | [diff] [blame] | 108 | } else |
| 109 | { |
| 110 | /* Initialize the whole drum set */ |
| 111 | for(a=0; a<128; a++) |
| 112 | drumUsed[a]=1; |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 113 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 114 | } |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 115 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 116 | int file = rb->open(filename, O_RDONLY); |
Stepan Moskovchenko | 68af7ba | 2006-05-07 07:12:07 +0000 | [diff] [blame] | 117 | if(file < 0) |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 118 | { |
Jens Arnold | b1f0049 | 2007-04-21 05:35:17 +0000 | [diff] [blame] | 119 | printf(""); |
| 120 | printf("No MIDI patchset found."); |
| 121 | printf("Please install the instruments."); |
| 122 | printf("See Rockbox page for more info."); |
Stepan Moskovchenko | 68af7ba | 2006-05-07 07:12:07 +0000 | [diff] [blame] | 123 | |
Jens Arnold | 4d6374c | 2007-03-16 21:56:08 +0000 | [diff] [blame] | 124 | rb->splash(HZ*2, "No Instruments"); |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 125 | return -1; |
| 126 | } |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 127 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 128 | char name[40]; |
| 129 | char fn[40]; |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 130 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 131 | /* Scan our config file and load the right patches as needed */ |
| 132 | int c = 0; |
Jens Arnold | 79c8a8c | 2007-03-17 09:02:53 +0000 | [diff] [blame] | 133 | name[0] = '\0'; |
Jens Arnold | b1f0049 | 2007-04-21 05:35:17 +0000 | [diff] [blame] | 134 | printf("Loading instruments"); |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 135 | for(a=0; a<128; a++) |
| 136 | { |
| 137 | while(readChar(file)!=' ' && !eof(file)); |
| 138 | readTextBlock(file, name); |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 139 | |
Nils Wallménius | 04b3435 | 2007-09-10 09:46:36 +0000 | [diff] [blame] | 140 | rb->snprintf(fn, 40, ROCKBOX_DIR "/patchset/%s.pat", name); |
Stepan Moskovchenko | b2f1b5d | 2006-05-01 23:22:59 +0000 | [diff] [blame] | 141 | /* printf("\nLOADING: <%s> ", fn); */ |
Stepan Moskovchenko | 5811214 | 2005-04-15 20:27:04 +0000 | [diff] [blame] | 142 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 143 | if(patchUsed[a]==1) |
| 144 | { |
| 145 | patchSet[a]=gusload(fn); |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 146 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 147 | if(patchSet[a] == NULL) /* There was an error loading it */ |
| 148 | return -1; |
| 149 | } |
Stepan Moskovchenko | 5811214 | 2005-04-15 20:27:04 +0000 | [diff] [blame] | 150 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 151 | while((c != '\n')) |
| 152 | c = readChar(file); |
| 153 | } |
| 154 | rb->close(file); |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 155 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 156 | file = rb->open(drumConfig, O_RDONLY); |
Stepan Moskovchenko | 68af7ba | 2006-05-07 07:12:07 +0000 | [diff] [blame] | 157 | if(file < 0) |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 158 | { |
Jens Arnold | 4d6374c | 2007-03-16 21:56:08 +0000 | [diff] [blame] | 159 | rb->splash(HZ*2, "Bad drum config. Did you install the patchset?"); |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 160 | return -1; |
| 161 | } |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 162 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 163 | /* Scan our config file and load the drum data */ |
| 164 | int idx=0; |
| 165 | char number[30]; |
Jens Arnold | b1f0049 | 2007-04-21 05:35:17 +0000 | [diff] [blame] | 166 | printf("Loading drums"); |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 167 | while(!eof(file)) |
| 168 | { |
| 169 | readTextBlock(file, number); |
| 170 | readTextBlock(file, name); |
Nils Wallménius | 04b3435 | 2007-09-10 09:46:36 +0000 | [diff] [blame] | 171 | rb->snprintf(fn, 40, ROCKBOX_DIR "/patchset/%s.pat", name); |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 172 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 173 | idx = rb->atoi(number); |
| 174 | if(idx == 0) |
| 175 | break; |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 176 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 177 | if(drumUsed[idx]==1) |
| 178 | { |
| 179 | drumSet[idx]=gusload(fn); |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 180 | if(drumSet[idx] == NULL) /* Error loading patch */ |
| 181 | return -1; |
| 182 | } |
Stepan Moskovchenko | 5811214 | 2005-04-15 20:27:04 +0000 | [diff] [blame] | 183 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 184 | while((c != '\n') && (c != 255) && (!eof(file))) |
| 185 | c = readChar(file); |
| 186 | } |
| 187 | rb->close(file); |
| 188 | return 0; |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 189 | } |
| 190 | |
Linus Nielsen Feltzing | 7c4b786 | 2007-04-11 10:48:50 +0000 | [diff] [blame] | 191 | #define getSample(s,wf) ((short *)(wf)->data)[s] |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 192 | |
Nils Wallménius | 6386dbe | 2007-09-30 11:21:25 +0000 | [diff] [blame] | 193 | void setPoint(struct SynthObject * so, int pt) ICODE_ATTR; |
Stepan Moskovchenko | b2f1b5d | 2006-05-01 23:22:59 +0000 | [diff] [blame] | 194 | void setPoint(struct SynthObject * so, int pt) |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 195 | { |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 196 | if(so->ch==9) /* Drums, no ADSR */ |
| 197 | { |
| 198 | so->curOffset = 1<<27; |
| 199 | so->curRate = 1; |
| 200 | return; |
| 201 | } |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 202 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 203 | if(so->wf==NULL) |
| 204 | { |
Jens Arnold | b1f0049 | 2007-04-21 05:35:17 +0000 | [diff] [blame] | 205 | printf("Crap... null waveform..."); |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 206 | exit(1); |
| 207 | } |
| 208 | if(so->wf->envRate==NULL) |
| 209 | { |
Jens Arnold | b1f0049 | 2007-04-21 05:35:17 +0000 | [diff] [blame] | 210 | printf("Waveform has no envelope set"); |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 211 | exit(1); |
| 212 | } |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 213 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 214 | so->curPoint = pt; |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 215 | |
Stepan Moskovchenko | b2f1b5d | 2006-05-01 23:22:59 +0000 | [diff] [blame] | 216 | int r; |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 217 | int rate = so->wf->envRate[pt]; |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 218 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 219 | r=3-((rate>>6) & 0x3); /* Some blatant Timidity code for rate conversion... */ |
| 220 | r*=3; |
| 221 | r = (rate & 0x3f) << r; |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 222 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 223 | /* |
| 224 | * Okay. This is the rate shift. Timidity defaults to 9, and sets |
| 225 | * it to 10 if you use the fast decay option. Slow decay sounds better |
| 226 | * on some files, except on some other files... you get chords that aren't |
| 227 | * done decaying yet.. and they dont harmonize with the next chord and it |
| 228 | * sounds like utter crap. Yes, even Timitidy does that. So I'm going to |
| 229 | * default this to 10, and maybe later have an option to set it to 9 |
| 230 | * for longer decays. |
| 231 | */ |
Stepan Moskovchenko | 414724e | 2007-09-30 09:01:38 +0000 | [diff] [blame] | 232 | so->curRate = r<<10; |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 233 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 234 | /* |
| 235 | * Do this here because the patches assume a 44100 sampling rate |
| 236 | * We've halved our sampling rate, ergo the ADSR code will be |
| 237 | * called half the time. Ergo, double the rate to keep stuff |
| 238 | * sounding right. |
Stepan Moskovchenko | b2f1b5d | 2006-05-01 23:22:59 +0000 | [diff] [blame] | 239 | * |
| 240 | * Or just move the 1 up one line to optimize a tiny bit. |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 241 | */ |
Stepan Moskovchenko | 94d9d15 | 2006-10-03 23:27:44 +0000 | [diff] [blame] | 242 | /* so->curRate = so->curRate << 1; */ |
Stepan Moskovchenko | 1f5fb99 | 2005-04-19 15:57:07 +0000 | [diff] [blame] | 243 | |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 244 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 245 | so->targetOffset = so->wf->envOffset[pt]<<(20); |
| 246 | if(pt==0) |
| 247 | so->curOffset = 0; |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 248 | } |
| 249 | |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 250 | inline void stopVoice(struct SynthObject * so) |
| 251 | { |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 252 | if(so->state == STATE_RAMPDOWN) |
| 253 | return; |
| 254 | so->state = STATE_RAMPDOWN; |
Stepan Moskovchenko | 80b4882 | 2006-10-02 04:13:33 +0000 | [diff] [blame] | 255 | so->decay = 0; |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 256 | } |
| 257 | |
Nils Wallménius | f619f81 | 2007-10-08 19:28:41 +0000 | [diff] [blame] | 258 | static inline int synthVoice(struct SynthObject * so) |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 259 | { |
Stepan Moskovchenko | b2f1b5d | 2006-05-01 23:22:59 +0000 | [diff] [blame] | 260 | struct GWaveform * wf; |
| 261 | register int s; |
| 262 | register unsigned int cpShifted; |
| 263 | register short s1; |
| 264 | register short s2; |
| 265 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 266 | wf = so->wf; |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 267 | |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 268 | |
Stepan Moskovchenko | 80b4882 | 2006-10-02 04:13:33 +0000 | [diff] [blame] | 269 | /* Is voice being ramped? */ |
| 270 | if(so->state == STATE_RAMPDOWN) |
| 271 | { |
| 272 | if(so->decay != 0) /* Ramp has been started */ |
| 273 | { |
| 274 | so->decay = so->decay / 2; |
| 275 | |
| 276 | if(so->decay < 10 && so->decay > -10) |
| 277 | so->isUsed = 0; |
| 278 | |
Stepan Moskovchenko | c84461f | 2006-10-03 21:09:47 +0000 | [diff] [blame] | 279 | return so->decay; |
Stepan Moskovchenko | 80b4882 | 2006-10-02 04:13:33 +0000 | [diff] [blame] | 280 | } |
| 281 | } else /* OK to advance voice */ |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 282 | { |
| 283 | so->cp += so->delta; |
| 284 | } |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 285 | |
Stepan Moskovchenko | 80b4882 | 2006-10-02 04:13:33 +0000 | [diff] [blame] | 286 | |
Stepan Moskovchenko | 94d9d15 | 2006-10-03 23:27:44 +0000 | [diff] [blame] | 287 | cpShifted = so->cp >> FRACTSIZE; |
Stepan Moskovchenko | 1f5fb99 | 2005-04-19 15:57:07 +0000 | [diff] [blame] | 288 | |
Stepan Moskovchenko | c84461f | 2006-10-03 21:09:47 +0000 | [diff] [blame] | 289 | |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 290 | |
Stepan Moskovchenko | b2f1b5d | 2006-05-01 23:22:59 +0000 | [diff] [blame] | 291 | s2 = getSample((cpShifted)+1, wf); |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 292 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 293 | /* LOOP_REVERSE|LOOP_PINGPONG = 24 */ |
Stepan Moskovchenko | 8b6d287 | 2007-09-27 03:59:33 +0000 | [diff] [blame] | 294 | if((wf->mode & (24)) && so->loopState == STATE_LOOPING && (cpShifted < (wf->startLoop))) |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 295 | { |
| 296 | if(wf->mode & LOOP_REVERSE) |
| 297 | { |
Stepan Moskovchenko | d1e3060 | 2007-09-29 02:20:49 +0000 | [diff] [blame] | 298 | cpShifted = wf->endLoop-(wf->startLoop-cpShifted); |
| 299 | so->cp = (cpShifted)<<FRACTSIZE; |
Stepan Moskovchenko | b2f1b5d | 2006-05-01 23:22:59 +0000 | [diff] [blame] | 300 | s2=getSample((cpShifted), wf); |
| 301 | } |
| 302 | else |
Stepan Moskovchenko | c84461f | 2006-10-03 21:09:47 +0000 | [diff] [blame] | 303 | { |
Stepan Moskovchenko | d1e3060 | 2007-09-29 02:20:49 +0000 | [diff] [blame] | 304 | so->delta = -so->delta; /* At this point cpShifted is wrong. We need to take a step */ |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 305 | so->loopDir = LOOPDIR_FORWARD; |
| 306 | } |
| 307 | } |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 308 | |
Stepan Moskovchenko | aaf3e32 | 2007-09-29 03:07:31 +0000 | [diff] [blame] | 309 | if((wf->mode & 28) && (cpShifted >= wf->endLoop)) |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 310 | { |
| 311 | so->loopState = STATE_LOOPING; |
| 312 | if((wf->mode & (24)) == 0) |
| 313 | { |
Stepan Moskovchenko | d1e3060 | 2007-09-29 02:20:49 +0000 | [diff] [blame] | 314 | cpShifted = wf->startLoop + (cpShifted-wf->endLoop); |
| 315 | so->cp = (cpShifted)<<FRACTSIZE; |
Stepan Moskovchenko | b2f1b5d | 2006-05-01 23:22:59 +0000 | [diff] [blame] | 316 | s2=getSample((cpShifted), wf); |
| 317 | } |
| 318 | else |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 319 | { |
| 320 | so->delta = -so->delta; |
| 321 | so->loopDir = LOOPDIR_REVERSE; |
| 322 | } |
| 323 | } |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 324 | |
Stepan Moskovchenko | c84461f | 2006-10-03 21:09:47 +0000 | [diff] [blame] | 325 | /* Have we overrun? */ |
| 326 | if( (cpShifted >= (wf->numSamples-1))) |
| 327 | { |
| 328 | so->cp -= so->delta; |
Stepan Moskovchenko | c84461f | 2006-10-03 21:09:47 +0000 | [diff] [blame] | 329 | cpShifted = so->cp >> FRACTSIZE; |
| 330 | s2 = getSample((cpShifted)+1, wf); |
Stepan Moskovchenko | c84461f | 2006-10-03 21:09:47 +0000 | [diff] [blame] | 331 | stopVoice(so); |
| 332 | } |
| 333 | |
| 334 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 335 | /* Better, working, linear interpolation */ |
Stepan Moskovchenko | 80b4882 | 2006-10-02 04:13:33 +0000 | [diff] [blame] | 336 | s1=getSample((cpShifted), wf); |
| 337 | |
Stepan Moskovchenko | 94d9d15 | 2006-10-03 23:27:44 +0000 | [diff] [blame] | 338 | s = s1 + ((signed)((s2 - s1) * (so->cp & ((1<<FRACTSIZE)-1)))>>FRACTSIZE); |
Stepan Moskovchenko | 1f5fb99 | 2005-04-19 15:57:07 +0000 | [diff] [blame] | 339 | |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 340 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 341 | if(so->curRate == 0) |
Stepan Moskovchenko | c84461f | 2006-10-03 21:09:47 +0000 | [diff] [blame] | 342 | { |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 343 | stopVoice(so); |
Stepan Moskovchenko | 94d9d15 | 2006-10-03 23:27:44 +0000 | [diff] [blame] | 344 | // so->isUsed = 0; |
| 345 | |
Stepan Moskovchenko | c84461f | 2006-10-03 21:09:47 +0000 | [diff] [blame] | 346 | } |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 347 | |
Stepan Moskovchenko | 80b4882 | 2006-10-02 04:13:33 +0000 | [diff] [blame] | 348 | if(so->ch != 9 && so->state != STATE_RAMPDOWN) /* Stupid ADSR code... and don't do ADSR for drums */ |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 349 | { |
| 350 | if(so->curOffset < so->targetOffset) |
| 351 | { |
| 352 | so->curOffset += (so->curRate); |
| 353 | if(so -> curOffset > so->targetOffset && so->curPoint != 2) |
| 354 | { |
| 355 | if(so->curPoint != 5) |
Stepan Moskovchenko | 94d9d15 | 2006-10-03 23:27:44 +0000 | [diff] [blame] | 356 | { |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 357 | setPoint(so, so->curPoint+1); |
Stepan Moskovchenko | 94d9d15 | 2006-10-03 23:27:44 +0000 | [diff] [blame] | 358 | } |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 359 | else |
Stepan Moskovchenko | c84461f | 2006-10-03 21:09:47 +0000 | [diff] [blame] | 360 | { |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 361 | stopVoice(so); |
Stepan Moskovchenko | c84461f | 2006-10-03 21:09:47 +0000 | [diff] [blame] | 362 | } |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 363 | } |
| 364 | } else |
| 365 | { |
| 366 | so->curOffset -= (so->curRate); |
| 367 | if(so -> curOffset < so->targetOffset && so->curPoint != 2) |
| 368 | { |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 369 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 370 | if(so->curPoint != 5) |
Stepan Moskovchenko | 94d9d15 | 2006-10-03 23:27:44 +0000 | [diff] [blame] | 371 | { |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 372 | setPoint(so, so->curPoint+1); |
Stepan Moskovchenko | 94d9d15 | 2006-10-03 23:27:44 +0000 | [diff] [blame] | 373 | } |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 374 | else |
Stepan Moskovchenko | c84461f | 2006-10-03 21:09:47 +0000 | [diff] [blame] | 375 | { |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 376 | stopVoice(so); |
Stepan Moskovchenko | c84461f | 2006-10-03 21:09:47 +0000 | [diff] [blame] | 377 | } |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 378 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 379 | } |
| 380 | } |
| 381 | } |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 382 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 383 | if(so->curOffset < 0) |
Stepan Moskovchenko | c84461f | 2006-10-03 21:09:47 +0000 | [diff] [blame] | 384 | { |
Stepan Moskovchenko | 94d9d15 | 2006-10-03 23:27:44 +0000 | [diff] [blame] | 385 | so->curOffset = so->targetOffset; |
| 386 | stopVoice(so); |
Stepan Moskovchenko | c84461f | 2006-10-03 21:09:47 +0000 | [diff] [blame] | 387 | } |
Stepan Moskovchenko | 94d9d15 | 2006-10-03 23:27:44 +0000 | [diff] [blame] | 388 | |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 389 | s = (s * (so->curOffset >> 22) >> 8); |
Stepan Moskovchenko | 1f5fb99 | 2005-04-19 15:57:07 +0000 | [diff] [blame] | 390 | |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 391 | |
Stepan Moskovchenko | 80b4882 | 2006-10-02 04:13:33 +0000 | [diff] [blame] | 392 | /* need to set ramp beginning */ |
| 393 | if(so->state == STATE_RAMPDOWN && so->decay == 0) |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 394 | { |
Stepan Moskovchenko | c84461f | 2006-10-03 21:09:47 +0000 | [diff] [blame] | 395 | so->decay = s*so->volscale>>14; |
| 396 | if(so->decay == 0) |
| 397 | so->decay = 1; /* stupid junk.. */ |
Stepan Moskovchenko | 9ec1ff8 | 2005-04-20 21:07:13 +0000 | [diff] [blame] | 398 | } |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 399 | |
Stepan Moskovchenko | 80b4882 | 2006-10-02 04:13:33 +0000 | [diff] [blame] | 400 | |
Stepan Moskovchenko | 28b5afd | 2006-05-03 19:32:22 +0000 | [diff] [blame] | 401 | /* Scaling by channel volume and note volume is done in sequencer.c */ |
| 402 | /* That saves us some multiplication and pointer operations */ |
| 403 | return s*so->volscale>>14; |
Stepan Moskovchenko | 215e492 | 2005-04-15 06:08:55 +0000 | [diff] [blame] | 404 | } |
| 405 | |
Nils Wallménius | f619f81 | 2007-10-08 19:28:41 +0000 | [diff] [blame] | 406 | /* synth num_samples samples and write them to the */ |
| 407 | /* buffer pointed to by buf_ptr */ |
| 408 | void synthSamples(int32_t *buf_ptr, unsigned int num_samples) ICODE_ATTR; |
| 409 | void synthSamples(int32_t *buf_ptr, unsigned int num_samples) |
| 410 | { |
| 411 | int i; |
| 412 | register int dL; |
| 413 | register int dR; |
| 414 | register int sample; |
| 415 | register struct SynthObject *voicept; |
| 416 | while(num_samples>0) |
| 417 | { |
| 418 | dL=0; |
| 419 | dR=0; |
| 420 | voicept=&voices[0]; |
| 421 | |
| 422 | for(i=MAX_VOICES; i > 0; i--) |
| 423 | { |
| 424 | if(voicept->isUsed==1) |
| 425 | { |
| 426 | sample = synthVoice(voicept); |
| 427 | dL += sample; |
| 428 | sample *= chPan[voicept->ch]; |
| 429 | dR += sample; |
| 430 | } |
| 431 | voicept++; |
| 432 | } |
| 433 | |
| 434 | dL = (dL << 7) - dR; |
| 435 | |
| 436 | /* combine the left and right 16 bit samples into 32 bits and write */ |
| 437 | /* to the buffer, left sample in the high word and right in the low word */ |
| 438 | *buf_ptr=(((dL&0x7FFF80) << 9) | ((dR&0x7FFF80) >> 7)); |
| 439 | |
| 440 | buf_ptr++; |
| 441 | num_samples--; |
| 442 | } |
| 443 | /* TODO: Automatic Gain Control, anyone? */ |
| 444 | /* Or, should this be implemented on the DSP's output volume instead? */ |
| 445 | |
| 446 | return; /* No more ghetto lowpass filter. Linear interpolation works well. */ |
| 447 | } |
| 448 | |