OSDN Git Service

Fix README.win32 for Win32 compilation.
[wavtool-pl/wavtool-pl.git] / src / wfd.c
1 /*
2     wavtool-pl
3     Copyright (C) 2011 Ying-Chun Liu (PaulLiu) <paulliu@debian.org>
4
5     This program is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdint.h>
23
24 #include <sndfile.h>
25
26 #include "wfh.h"
27 #include "wfd.h"
28
29 /**
30  * Create an empty dat file
31  *
32  * @param filename the filename of dat file
33  */
34 void wfd_init(const char *filename) {
35   FILE *file1;
36   file1 = fopen(filename,"w");
37   if (file1) {
38     fclose(file1);
39   }
40 }
41
42 /**
43  * convert micro seconds to samples
44  *
45  * @param time time in ms
46  * @return samples
47  */
48 int wfd_ms2samples(double time) {
49   double samples_f;
50   int samples;
51   samples_f = ((double)wfh_samplerate) * time / 1000.0;
52   samples = (int)samples_f;
53   return samples;
54 }
55
56 /**
57  * skip the file by microseconds
58  *
59  * @param inputfile the file descriptor
60  * @param time time in ms
61  */
62 void wfd_skip(FILE *inputfile, double time) {
63   int samples;
64   samples = wfd_ms2samples(time);
65   fseek(inputfile,SEEK_CUR,samples*wfh_channels*(wfh_bits/8));
66 }
67
68 /**
69  * Get volume factor by frame number
70  *
71  * @param frame Current frame number
72  * @param p the p vector, 7 elements, sort by time (ms)
73  * @param v the v vector, 7 elements, sort based on p (%)
74  * @return the volume factor for frame. (%)
75  */
76 double wfd_append_linear_volume(int frame, const int *p, const double *v) {
77   double ret=0.0;
78   int i;
79   for (i=0; i<6; i++) {
80     if (p[i] <= frame && frame < p[i+1]) {
81       ret = v[i] + (v[i+1]-v[i]) * (((double)(frame-p[i])) / (((double)(p[i+1]-p[i]))));
82       break;
83     }
84   }
85   return ret;
86 }
87
88 /**
89  * mix sample A with sample B
90  *
91  * @param a sample A
92  * @param b sample B
93  * @return sample of A mix B
94  */
95 int16_t wfd_mix(int16_t a, int16_t b) {
96   int a_t;
97   int b_t;
98   int r1;
99   int16_t ret=0;
100
101   a_t = ((int)a)+32768;
102   b_t = ((int)b)+32768;
103
104   if (a_t <= 32768 && b_t <= 32768) {
105     r1 = (a_t * b_t) / 32768;
106   } else {
107     r1 = 2*(a_t+b_t) - (a_t*b_t)/32768 - 65536;
108     if (r1>=65536) {
109       r1 = 65535;
110     }
111   }
112   r1 = r1 - 32768;
113   ret = ((int16_t)r1);
114   return ret;
115 }
116
117
118 /**
119  * append data to dat file
120  *
121  * @param outputfilename the filename of output file
122  * @param inputfilename the filename of input file
123  * @param offset skip the ms in input file
124  * @param length the time in ms have to be handled
125  * @param ovr the overlap of output file and input file (ms)
126  * @param p the p position array
127  * @param v the v volume array
128  * @return 0 - ok, nonzero - error
129  */
130 int wfd_append(const char *outputfilename, const char *inputfilename,
131                 double offset, double length,
132                 double ovr, const double *p, const double *v) {
133   int ret=0;
134   FILE *outfile=NULL;
135   SNDFILE *inputfile=NULL;
136   SF_INFO inputfileinfo;
137   int16_t *buf=NULL;
138   int p_f[7];
139   double v_f[7];
140   int currentFrame=0;
141   int ovrFrames=0;
142   int outputFrames=0;
143   int i;
144   int16_t sum;
145   int c1,c2;
146
147   memset(&inputfileinfo,0,sizeof(SF_INFO));
148   outfile = fopen(outputfilename,"r+b");
149   fseek(outfile,0,SEEK_END);
150   if (inputfilename) {
151     inputfile = sf_open(inputfilename,SFM_READ,&inputfileinfo);
152     sf_command(inputfile,SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE);
153   } else {
154     inputfile=NULL;
155   }
156   outputFrames = wfd_ms2samples(length);
157
158   /* handle offset */
159   if (wfd_ms2samples(offset)>0) {
160     if (inputfile) {
161       sf_seek(inputfile,wfd_ms2samples(offset),SEEK_SET);
162     }
163   }
164
165   /* pre-calculate volume */
166   p_f[0]=0;
167   for (i=0; i<2; i++) {
168     p_f[i+1] = wfd_ms2samples(p[i]) + p_f[i];
169   }
170   p_f[3] = wfd_ms2samples(p[4]) + p_f[2];
171   p_f[6] = outputFrames;
172   p_f[5] = p_f[6] - wfd_ms2samples(p[3]);
173   p_f[4] = p_f[5] - wfd_ms2samples(p[2]);
174
175   v_f[0]=0.0;
176   for (i=0;i<2; i++) {
177     v_f[i+1] = v[i];
178   }
179   v_f[3]=v[4];
180   v_f[4]=v[2];
181   v_f[5]=v[3];
182   v_f[6]=0.0;
183
184   if (p_f[1]==p_f[2]) {
185     v_f[1]=v_f[2];
186   }
187   if (p_f[0]==p_f[1]) {
188     v_f[0]=v_f[1];
189   }
190   if (p_f[5]==p_f[4]) {
191     v_f[5]=v_f[4];
192   }
193   if (p_f[6]==p_f[5]) {
194     v_f[6]=v_f[5];
195   }
196
197   ovrFrames = wfd_ms2samples(ovr);
198   if (ovrFrames > 0) {
199     fseek(outfile,(-1)*wfh_channels*(wfh_bits/8)*ovrFrames,SEEK_END);
200   } else if (ovr < 0.0) {
201     /* output blank samples */
202     int ovrSamples=0;
203     int i,j,k;
204     ovrSamples = wfd_ms2samples(-ovr);
205     for (i=0; i<ovrSamples; i++) {
206       for (j=0; j<wfh_channels; j++) {
207         for (k=0; k<(wfh_bits/8); k++) {
208           fwrite("\0",1,1,outfile);
209         }
210       }
211     }
212     fflush(outfile);
213     fseek(outfile,0,SEEK_CUR);
214     ovr=0.0;
215     ovrFrames=0;
216   }
217
218   /* output */
219   buf = (int16_t *)malloc(sizeof(int16_t)*(inputfileinfo.channels));
220   memset(buf,0,sizeof(int16_t)*(inputfileinfo.channels));
221
222   currentFrame = 0;
223   for ( ; outputFrames > 0; outputFrames--) {
224     if (inputfile) {
225       int result1;
226       result1 = (int)sf_readf_short(inputfile,buf,1);
227       if (result1 < 1) {
228         memset(buf,0,sizeof(int16_t)*(inputfileinfo.channels));
229         sf_close(inputfile);
230         inputfile=NULL;
231       }
232     }
233     /* simple mix if there are multi-channels */
234     sum=0;
235     for (i=0; i<inputfileinfo.channels; i++) {
236       sum += buf[i];
237     }
238     /* modify the volume */
239     if (inputfileinfo.channels>0) {
240       double vf;
241       sum = sum/inputfileinfo.channels;
242       vf = wfd_append_linear_volume(currentFrame,p_f,v_f);
243       sum = (int16_t)(((double)sum)*(vf/100.0));
244     } else {
245       sum=0;
246     }
247     if (ovrFrames>0) {
248       int16_t d,r;
249       c1 = fgetc(outfile);
250       if (c1 == EOF) {
251         ovrFrames=0;
252         goto wfd_append_normal;
253       }
254       c2 = fgetc(outfile);
255       if (c2 == EOF) {
256         ovrFrames=0;
257         goto wfd_append_normal;
258       }
259       fseek(outfile,-2,SEEK_CUR);
260       d = (c1 & (0x00ff)) | (((c2 & 0x00ff) << 8) & 0xff00);
261       r = wfd_mix(sum,d);
262       fputc( (int)((r) & (0x00ff)), outfile);
263       fputc( (int)((r>>8) & 0x00ff), outfile);
264       fflush(outfile);
265       fseek(outfile,0,SEEK_CUR);
266       ovrFrames--;
267     } else {
268     wfd_append_normal:
269       fputc( (int)((sum) & (0x00ff)), outfile);
270       fputc( (int)((sum>>8) & 0x00ff), outfile);
271       fflush(outfile);
272       fseek(outfile,0,SEEK_CUR);
273     }
274     currentFrame++;
275   }
276
277   if (!inputfile) {
278     sf_close(inputfile);
279     inputfile=NULL;
280   }
281   if (!buf) {
282     free(buf);
283     buf=NULL;
284   }
285   ret = ftell(outfile);
286   fclose(outfile);
287   outfile=NULL;
288   return ret;
289 }