2 * Patch transfer callback for Emu10k1
4 * Copyright (C) 2000 Takashi iwai <tiwai@suse.de>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * All the code for loading in a patch. There is very little that is
22 * chip specific here. Just the actual writing to the board.
25 #include "emu10k1_synth_local.h"
29 #define BLANK_LOOP_START 4
30 #define BLANK_LOOP_END 8
31 #define BLANK_LOOP_SIZE 12
32 #define BLANK_HEAD_SIZE 32
35 * allocate a sample block and copy data from userspace
38 snd_emu10k1_sample_new(struct snd_emux
*rec
, struct snd_sf_sample
*sp
,
39 struct snd_util_memhdr
*hdr
,
40 const void __user
*data
, long count
)
43 int truesize
, size
, loopsize
, blocksize
;
44 int loopend
, sampleend
;
45 unsigned int start_addr
;
46 struct snd_emu10k1
*emu
;
49 snd_assert(sp
!= NULL
, return -EINVAL
);
50 snd_assert(hdr
!= NULL
, return -EINVAL
);
52 if (sp
->v
.size
== 0) {
53 snd_printd("emu: rom font for sample %d\n", sp
->v
.sample
);
57 /* recalculate address offset */
58 sp
->v
.end
-= sp
->v
.start
;
59 sp
->v
.loopstart
-= sp
->v
.start
;
60 sp
->v
.loopend
-= sp
->v
.start
;
63 /* some samples have invalid data. the addresses are corrected in voice info */
64 sampleend
= sp
->v
.end
;
65 if (sampleend
> sp
->v
.size
)
66 sampleend
= sp
->v
.size
;
67 loopend
= sp
->v
.loopend
;
68 if (loopend
> sampleend
)
71 /* be sure loop points start < end */
72 if (sp
->v
.loopstart
>= sp
->v
.loopend
) {
73 int tmp
= sp
->v
.loopstart
;
74 sp
->v
.loopstart
= sp
->v
.loopend
;
78 /* compute true data size to be loaded */
79 truesize
= sp
->v
.size
+ BLANK_HEAD_SIZE
;
81 #if 0 /* not supported */
82 if (sp
->v
.mode_flags
& (SNDRV_SFNT_SAMPLE_BIDIR_LOOP
|SNDRV_SFNT_SAMPLE_REVERSE_LOOP
))
83 loopsize
= sp
->v
.loopend
- sp
->v
.loopstart
;
86 if (sp
->v
.mode_flags
& SNDRV_SFNT_SAMPLE_NO_BLANK
)
87 truesize
+= BLANK_LOOP_SIZE
;
89 /* try to allocate a memory block */
91 if (! (sp
->v
.mode_flags
& SNDRV_SFNT_SAMPLE_8BITS
))
93 sp
->block
= snd_emu10k1_synth_alloc(emu
, blocksize
);
94 if (sp
->block
== NULL
) {
95 snd_printd("emu10k1: synth malloc failed (size=%d)\n", blocksize
);
96 /* not ENOMEM (for compatibility with OSS) */
99 /* set the total size */
100 sp
->v
.truesize
= blocksize
;
102 /* write blank samples at head */
104 size
= BLANK_HEAD_SIZE
;
105 if (! (sp
->v
.mode_flags
& SNDRV_SFNT_SAMPLE_8BITS
))
107 snd_assert(offset
+ size
<= blocksize
, return -EINVAL
);
108 snd_emu10k1_synth_bzero(emu
, sp
->block
, offset
, size
);
111 /* copy start->loopend */
113 if (! (sp
->v
.mode_flags
& SNDRV_SFNT_SAMPLE_8BITS
))
115 snd_assert(offset
+ size
<= blocksize
, return -EINVAL
);
116 if (snd_emu10k1_synth_copy_from_user(emu
, sp
->block
, offset
, data
, size
)) {
117 snd_emu10k1_synth_free(emu
, sp
->block
);
124 #if 0 /* not suppported yet */
125 /* handle reverse (or bidirectional) loop */
126 if (sp
->v
.mode_flags
& (SNDRV_SFNT_SAMPLE_BIDIR_LOOP
|SNDRV_SFNT_SAMPLE_REVERSE_LOOP
)) {
127 /* copy loop in reverse */
128 if (! (sp
->v
.mode_flags
& SNDRV_SFNT_SAMPLE_8BITS
)) {
130 unsigned short *wblock
= (unsigned short*)block
;
131 woffset
= offset
/ 2;
132 snd_assert(offset
+ loopsize
*2 <= blocksize
, return -EINVAL
);
133 for (i
= 0; i
< loopsize
; i
++)
134 wblock
[woffset
+ i
] = wblock
[woffset
- i
-1];
135 offset
+= loopsize
* 2;
137 snd_assert(offset
+ loopsize
<= blocksize
, return -EINVAL
);
138 for (i
= 0; i
< loopsize
; i
++)
139 block
[offset
+ i
] = block
[offset
- i
-1];
143 /* modify loop pointers */
144 if (sp
->v
.mode_flags
& SNDRV_SFNT_SAMPLE_BIDIR_LOOP
) {
145 sp
->v
.loopend
+= loopsize
;
147 sp
->v
.loopstart
+= loopsize
;
148 sp
->v
.loopend
+= loopsize
;
150 /* add sample pointer */
151 sp
->v
.end
+= loopsize
;
155 /* loopend -> sample end */
156 size
= sp
->v
.size
- loopend
;
157 snd_assert(size
>= 0, return -EINVAL
);
158 if (! (sp
->v
.mode_flags
& SNDRV_SFNT_SAMPLE_8BITS
))
160 if (snd_emu10k1_synth_copy_from_user(emu
, sp
->block
, offset
, data
, size
)) {
161 snd_emu10k1_synth_free(emu
, sp
->block
);
167 /* clear rest of samples (if any) */
168 if (offset
< blocksize
)
169 snd_emu10k1_synth_bzero(emu
, sp
->block
, offset
, blocksize
- offset
);
171 if (sp
->v
.mode_flags
& SNDRV_SFNT_SAMPLE_NO_BLANK
) {
172 /* if no blank loop is attached in the sample, add it */
173 if (sp
->v
.mode_flags
& SNDRV_SFNT_SAMPLE_SINGLESHOT
) {
174 sp
->v
.loopstart
= sp
->v
.end
+ BLANK_LOOP_START
;
175 sp
->v
.loopend
= sp
->v
.end
+ BLANK_LOOP_END
;
179 #if 0 /* not supported yet */
180 if (sp
->v
.mode_flags
& SNDRV_SFNT_SAMPLE_UNSIGNED
) {
181 /* unsigned -> signed */
182 if (! (sp
->v
.mode_flags
& SNDRV_SFNT_SAMPLE_8BITS
)) {
183 unsigned short *wblock
= (unsigned short*)block
;
184 for (i
= 0; i
< truesize
; i
++)
187 for (i
= 0; i
< truesize
; i
++)
193 /* recalculate offset */
194 start_addr
= BLANK_HEAD_SIZE
* 2;
195 if (! (sp
->v
.mode_flags
& SNDRV_SFNT_SAMPLE_8BITS
))
197 sp
->v
.start
+= start_addr
;
198 sp
->v
.end
+= start_addr
;
199 sp
->v
.loopstart
+= start_addr
;
200 sp
->v
.loopend
+= start_addr
;
206 * free a sample block
209 snd_emu10k1_sample_free(struct snd_emux
*rec
, struct snd_sf_sample
*sp
,
210 struct snd_util_memhdr
*hdr
)
212 struct snd_emu10k1
*emu
;
215 snd_assert(sp
!= NULL
, return -EINVAL
);
216 snd_assert(hdr
!= NULL
, return -EINVAL
);
219 snd_emu10k1_synth_free(emu
, sp
->block
);