OSDN Git Service

f4bc7520b6bc0b6a263082116b3fc5ba46252fc3
[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   outputFrames = wfd_ms2samples(length);
126
127   /* handle offset */
128   if (wfd_ms2samples(offset)>0) {
129     if (inputfile) {
130       sf_seek(inputfile,wfd_ms2samples(offset),SEEK_SET);
131     }
132   }
133
134   /* pre-calculate volume */
135   p_f[0]=0;
136   for (i=0; i<2; i++) {
137     p_f[i+1] = wfd_ms2samples(p[i]) + p_f[i];
138   }
139   p_f[3] = wfd_ms2samples(p[4]) + p_f[2];
140   p_f[6] = outputFrames;
141   p_f[5] = p_f[6] - wfd_ms2samples(p[3]);
142   p_f[4] = p_f[5] - wfd_ms2samples(p[2]);
143
144   v_f[0]=0.0;
145   for (i=0;i<2; i++) {
146     v_f[i+1] = v[i];
147   }
148   v_f[3]=v[4];
149   v_f[4]=v[2];
150   v_f[5]=v[3];
151   v_f[6]=0.0;
152
153   if (p_f[1]==p_f[2]) {
154     v_f[1]=v_f[2];
155   }
156   if (p_f[0]==p_f[1]) {
157     v_f[0]=v_f[1];
158   }
159   if (p_f[5]==p_f[4]) {
160     v_f[5]=v_f[4];
161   }
162   if (p_f[6]==p_f[5]) {
163     v_f[6]=v_f[5];
164   }
165
166   ovrFrames = wfd_ms2samples(ovr);
167   if (ovrFrames > 0) {
168     fseek(outfile,(-1)*wfh_channels*(wfh_bits/8)*ovrFrames,SEEK_END);
169   } else if (ovr < 0.0) {
170     /* output blank samples */
171     int ovrSamples=0;
172     int i,j,k;
173     ovrSamples = wfd_ms2samples(-ovr);
174     for (i=0; i<ovrSamples; i++) {
175       for (j=0; j<wfh_channels; j++) {
176         for (k=0; k<(wfh_bits/8); k++) {
177           fwrite("\0",1,1,outfile);
178         }
179       }
180     }
181     ovr=0.0;
182     ovrFrames=0;
183   }
184
185   /* output */
186   buf = (short *)malloc(sizeof(short)*(inputfileinfo.channels));
187   memset(buf,0,sizeof(short)*(inputfileinfo.channels));
188
189   currentFrame = 0;
190   for ( ; outputFrames > 0; outputFrames--) {
191     if (inputfile) {
192       int result1;
193       result1 = sf_readf_short(inputfile,buf,1);
194       if (result1 < 1) {
195         memset(buf,0,sizeof(short)*(inputfileinfo.channels));
196         sf_close(inputfile);
197         inputfile=NULL;
198       }
199     }
200     /* simple mix if there are multi-channels */
201     sum=0;
202     for (i=0; i<inputfileinfo.channels; i++) {
203       sum += buf[i];
204     }
205     /* modify the volume */
206     if (inputfileinfo.channels>0) {
207       double vf;
208       sum = sum/inputfileinfo.channels;
209       vf = wfd_append_linear_volume(currentFrame,p_f,v_f);
210       sum = (short)(((double)sum)*(vf/100.0));
211     } else {
212       sum=0;
213     }
214     if (ovrFrames>0) {
215       short d,r;
216       c1 = fgetc(outfile);
217       if (c1 == EOF) {
218         ovrFrames=0;
219         goto wfd_append_normal;
220       }
221       c2 = fgetc(outfile);
222       if (c2 == EOF) {
223         ovrFrames=0;
224         goto wfd_append_normal;
225       }
226       fseek(outfile,-2,SEEK_CUR);
227       d = (c1 & (0x00ff)) | (((c2 & 0x00ff) << 8) & 0xff00);
228       r = sum+d;
229       fputc( (char)(r & (0x00ff)), outfile);
230       fputc( (char)((r>>8) & 0x00ff), outfile);
231       ovrFrames--;
232     } else {
233     wfd_append_normal:
234       fputc( (char)(sum & (0x00ff)), outfile);
235       fputc( (char)((sum>>8) & 0x00ff), outfile);
236     }
237     currentFrame++;
238   }
239
240   if (!inputfile) {
241     sf_close(inputfile);
242     inputfile=NULL;
243   }
244   if (!buf) {
245     free(buf);
246     buf=NULL;
247   }
248   ret = ftell(outfile);
249   fclose(outfile);
250   outfile=NULL;
251   return ret;
252 }