1 /*
2  * Copyright (C) 2008-2017 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2009 David Robillard <d@drobilla.net>
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 2 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 along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #include "ardour/caimportable.h"
21 #include <sndfile.h>
22 #include "pbd/error.h"
23 
24 #include "pbd/i18n.h"
25 
26 using namespace ARDOUR;
27 using namespace std;
28 using namespace PBD;
29 
CAImportableSource(const string & path)30 CAImportableSource::CAImportableSource (const string& path)
31 {
32 	try {
33 		af.Open (path.c_str());
34 
35 		CAStreamBasicDescription file_format (af.GetFileDataFormat());
36 		CAStreamBasicDescription client_format (file_format);
37 
38 		/* set canonial form (PCM, native float packed, 32 bit, with the correct number of channels
39 		   and interleaved (since we plan to deinterleave ourselves)
40 		*/
41 
42 		client_format.SetCanonical(client_format.NumberChannels(), true);
43 		af.SetClientFormat (client_format);
44 
45 	} catch (CAXException& cax) {
46                 //Don't report an error here since there is one higher up in import.
47                 //Since libsndfile gets tried second, any failures here may show as
48                 //invalid errors in the Error log.
49 		throw failed_constructor ();
50 	}
51 
52 }
53 
~CAImportableSource()54 CAImportableSource::~CAImportableSource ()
55 {
56 }
57 
58 samplecnt_t
read(Sample * buffer,samplecnt_t nframes)59 CAImportableSource::read (Sample* buffer, samplecnt_t nframes)
60 {
61 	samplecnt_t nread = 0;
62 	AudioBufferList abl;
63 	samplecnt_t per_channel;
64 	bool at_end = false;
65 
66 	abl.mNumberBuffers = 1;
67 	abl.mBuffers[0].mNumberChannels = channels();
68 
69 	per_channel = nframes / abl.mBuffers[0].mNumberChannels;
70 
71 	while (nread < per_channel) {
72 
73 		UInt32 new_cnt = per_channel - nread;
74 
75 		abl.mBuffers[0].mDataByteSize = new_cnt * abl.mBuffers[0].mNumberChannels * sizeof(Sample);
76 		abl.mBuffers[0].mData = buffer + nread;
77 
78 		try {
79 			af.Read (new_cnt, &abl);
80 		} catch (CAXException& cax) {
81 			error << string_compose("CAImportable: %1", cax.mOperation);
82 			return -1;
83 		}
84 
85 		if (new_cnt == 0) {
86 			/* EOF */
87 			at_end = true;
88 			break;
89 		}
90 
91 		nread += new_cnt;
92 	}
93 
94 	if (!at_end && nread < per_channel) {
95 		return 0;
96 	} else {
97 		return nread * abl.mBuffers[0].mNumberChannels;
98 	}
99 }
100 
101 uint
channels() const102 CAImportableSource::channels () const
103 {
104 	return af.GetFileDataFormat().NumberChannels();
105 }
106 
107 samplecnt_t
length() const108 CAImportableSource::length () const
109 {
110 	return af.GetNumberFrames();
111 }
112 
113 samplecnt_t
samplerate() const114 CAImportableSource::samplerate () const
115 {
116 	CAStreamBasicDescription client_asbd;
117 
118 	try {
119 		client_asbd = af.GetClientDataFormat ();
120 	} catch (CAXException& cax) {
121 		error << string_compose ("CAImportable: %1", cax.mOperation) << endmsg;
122 		return 0.0;
123 	}
124 
125 	return client_asbd.mSampleRate;
126 }
127 
128 void
seek(samplepos_t pos)129 CAImportableSource::seek (samplepos_t pos)
130 {
131 	try {
132 		af.Seek (pos);
133 	} catch (CAXException& cax) {
134 		error << string_compose ("CAImportable: %1 to %2", cax.mOperation, pos) << endmsg;
135 	}
136 }
137 
138 
139 samplepos_t
natural_position() const140 CAImportableSource::natural_position () const
141 {
142 	// TODO: extract timecode, if any
143 	return 0;
144 }
145