OSDN Git Service

31f8252f349eb8542ad26d578487c5ea443fb615
[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
23 #include <sndfile.h>
24
25 #include "wfh.h"
26 #include "wfd.h"
27
28 /**
29  * Create an empty dat file
30  *
31  * @param filename the filename of dat file
32  */
33 void wfd_init(const char *filename) {
34   FILE *file1;
35   file1 = fopen(filename,"w");
36   if (file1) {
37     fclose(file1);
38   }
39 }
40
41 /**
42  * convert micro seconds to samples
43  *
44  * @param time time in ms
45  * @return samples
46  */
47 int wfd_ms2samples(double time) {
48   double samples_f;
49   int samples;
50   samples_f = ((double)wfh_samplerate) * time / 1000.0;
51   samples = (int)samples_f;
52   return samples;
53 }
54
55 /**
56  * skip the file by microseconds
57  *
58  * @param inputfile the file descriptor
59  * @param time time in ms
60  */
61 void wfd_skip(FILE *inputfile, double time) {
62   int samples;
63   samples = wfd_ms2samples(time);
64   fseek(inputfile,SEEK_CUR,samples*wfh_channels*(wfh_bits/8));
65 }
66
67 /**
68  * Get volume factor by frame number
69  *
70  * @param frame Current frame number
71  * @param p the p vector, 7 elements, sort by time (ms)
72  * @param v the v vector, 7 elements, sort based on p (%)
73  * @return the volume factor for frame. (%)
74  */
75 double wfd_append_linear_volume(int frame, const int *p, const double *v) {
76   double ret=0.0;
77   int i;
78   for (i=0; i<6; i++) {
79     if (p[i] <= frame && frame < p[i+1]) {
80       ret = v[i] + (v[i+1]-v[i]) * (((double)(frame-p[i])) / (((double)(p[i+1]-p[i]))));
81       break;
82     }
83   }
84   return ret;
85 }
86
87 /**
88  * append data to dat file
89  *
90  * @param outputfilename the filename of output file
91  * @param inputfilename the filename of input file
92  * @param offset skip the ms in input file
93  * @param length the time in ms have to be handled
94  * @param ovr the overlap of output file and input file (ms)
95  * @param p the p position array
96  * @param v the v volume array
97  * @return 0 - ok, nonzero - error
98  */
99 int wfd_append(const char *outputfilename, const char *inputfilename,
100                 double offset, double length,
101                 double ovr, const double *p, const double *v) {
102   int ret=0;
103   FILE *outfile=NULL;
104   SNDFILE *inputfile=NULL;
105   SF_INFO inputfileinfo;
106   short *buf=NULL;
107   int p_f[7];
108   double v_f[7];
109   int currentFrame=0;
110   int ovrFrames=0;
111   int outputFrames=0;
112   int i;
113   short sum;
114   int c1,c2;
115
116   memset(&inputfileinfo,0,sizeof(SF_INFO));
117   outfile = fopen(outputfilename,"r+");
118   fseek(outfile,0,SEEK_END);
119   if (inputfilename) {
120     inputfile = sf_open(inputfilename,SFM_READ,&inputfileinfo);
121     sf_command(inputfile,SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE);
122   } else {
123     inputfile=NULL;
124   }
125
126   /* handle offset */
127   if (wfd_ms2samples(offset)>0) {
128     sf_seek(inputfile,wfd_ms2samples(offset),SEEK_SET);
129   }
130
131   /* pre-calculate volume */
132   p_f[0]=0;
133   for (i=0; i<2; i++) {
134     p_f[i+1] = wfd_ms2samples(p[i]) + p_f[i];
135   }
136   p_f[3] = wfd_ms2samples(p[4]) + p_f[2];
137   p_f[6]=inputfileinfo.frames;
138   p_f[5] = p_f[6] - wfd_ms2samples(p[3]);
139   p_f[4] = p_f[5] - wfd_ms2samples(p[2]);
140
141   v_f[0]=0.0;
142   for (i=0;i<2; i++) {
143     v_f[i+1] = v[i];
144   }
145   v_f[3]=v[4];
146   v_f[4]=v[2];
147   v_f[5]=v[3];
148   v_f[6]=0.0;
149
150   if (p_f[1]==p_f[2]) {
151     v_f[1]=v_f[2];
152   }
153   if (p_f[0]==p_f[1]) {
154     v_f[0]=v_f[1];
155   }
156   if (p_f[5]==p_f[4]) {
157     v_f[5]=v_f[4];
158   }
159   if (p_f[6]==p_f[5]) {
160     v_f[6]=v_f[5];
161   }
162
163   ovrFrames = wfd_ms2samples(ovr);
164   if (ovrFrames > 0) {
165     fseek(outfile,(-1)*wfh_channels*(wfh_bits/8)*ovrFrames,SEEK_END);
166   } else if (ovr < 0.0) {
167     /* output blank samples */
168     int ovrSamples=0;
169     int i,j,k;
170     ovrSamples = wfd_ms2samples(-ovr);
171     for (i=0; i<ovrSamples; i++) {
172       for (j=0; j<wfh_channels; j++) {
173         for (k=0; k<(wfh_bits/8); k++) {
174           fwrite("\0",1,1,outfile);
175         }
176       }
177     }
178     ovr=0.0;
179     ovrFrames=0;
180   }
181
182   /* output */
183   buf = (short *)malloc(sizeof(short)*(inputfileinfo.channels));
184   memset(buf,0,sizeof(short)*(inputfileinfo.channels));
185   outputFrames = wfd_ms2samples(length);
186
187   currentFrame = 0;
188   for ( ; outputFrames > 0; outputFrames--) {
189     if (inputfile) {
190       int result1;
191       result1 = sf_readf_short(inputfile,buf,1);
192       if (result1 < 1) {
193         memset(buf,0,sizeof(short)*(inputfileinfo.channels));
194         sf_close(inputfile);
195         inputfile=NULL;
196       }
197     }
198     /* simple mix if there are multi-channels */
199     sum=0;
200     for (i=0; i<inputfileinfo.channels; i++) {
201       sum += buf[i];
202     }
203     /* modify the volume */
204     if (inputfileinfo.channels>0) {
205       double vf;
206       sum = sum/inputfileinfo.channels;
207       vf = wfd_append_linear_volume(currentFrame,p_f,v_f);
208       sum = (short)(((double)sum)*(vf/100.0));
209     } else {
210       sum=0;
211     }
212     if (ovrFrames>0) {
213       short d,r;
214       c1 = fgetc(outfile);
215       if (c1 == EOF) {
216         ovrFrames=0;
217         goto wfd_append_normal;
218       }
219       c2 = fgetc(outfile);
220       if (c2 == EOF) {
221         ovrFrames=0;
222         goto wfd_append_normal;
223       }
224       fseek(outfile,-2,SEEK_CUR);
225       d = (c1 & (0x00ff)) | ((c2 & 0x00ff) << 8);
226       r = sum+d;
227       fputc( (char)(r & (0x00ff)), outfile);
228       fputc( (char)((r>>8) & 0x00ff), outfile);
229       ovrFrames--;
230     } else {
231     wfd_append_normal:
232       fputc( (char)(sum & (0x00ff)), outfile);
233       fputc( (char)((sum>>8) & 0x00ff), outfile);
234     }
235     currentFrame++;
236   }
237
238   if (!inputfile) {
239     sf_close(inputfile);
240     inputfile=NULL;
241   }
242   if (!buf) {
243     free(buf);
244     buf=NULL;
245   }
246   ret = ftell(outfile);
247   fclose(outfile);
248   outfile=NULL;
249   return ret;
250 }