├── .gitattributes
├── .github
└── workflows
│ └── build.yml
├── .gitignore
├── Directory.Build.props
├── LICENSE
├── README.md
└── src
├── AudioInfo.cs
├── Effects
├── AllPassFilterEffect.cs
├── BandPassFilterEffect.cs
├── BandRejectFilterEffect.cs
├── BaseEffect.cs
├── BassEffect.cs
├── ContrastEffect.cs
├── HighPassFilterEffect.cs
├── IBaseEffect.cs
├── LoudnessEffect.cs
├── LowPassFilterEffect.cs
├── NoiseProfileEffect.cs
├── NoiseReductionEffect.cs
├── ReverseEffect.cs
├── SpeedEffect.cs
├── TempoEffect.cs
├── TrebleEffect.cs
├── TremoloEffect.cs
├── TrimEffect.cs
├── Types
│ ├── FilterType.cs
│ ├── Frequency.cs
│ ├── FrequencyUnits.cs
│ ├── GainType.cs
│ ├── OptimizationType.cs
│ ├── Position.cs
│ ├── PositionFrom.cs
│ ├── Width.cs
│ └── WidthUnits.cs
└── VolumeEffect.cs
├── Events.cs
├── Exceptions
├── SoxEffectException.cs
├── SoxException.cs
└── SoxUnexpectedOutputException.cs
├── FormatOptions.cs
├── FormattedSize.cs
├── InputFile.cs
├── OutputFormatOptions.cs
├── Resources.Designer.cs
├── Resources.resx
├── Sox.cs
├── SoxProcess.cs
├── SoxSharp.csproj
├── SoxSharp.sln
├── Types.cs
└── Utils.cs
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: windows-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v2
16 | - name: Setup .NET
17 | uses: actions/setup-dotnet@v1
18 | with:
19 | dotnet-version: 5.0.x
20 | - name: Restore dependencies
21 | run: dotnet restore src\SoxSharp.sln
22 | - name: Build
23 | run: dotnet build --no-restore src\SoxSharp.sln
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 | *.VC.VC.opendb
85 |
86 | # Visual Studio profiler
87 | *.psess
88 | *.vsp
89 | *.vspx
90 | *.sap
91 |
92 | # TFS 2012 Local Workspace
93 | $tf/
94 |
95 | # Guidance Automation Toolkit
96 | *.gpState
97 |
98 | # ReSharper is a .NET coding add-in
99 | _ReSharper*/
100 | *.[Rr]e[Ss]harper
101 | *.DotSettings.user
102 |
103 | # JustCode is a .NET coding add-in
104 | .JustCode
105 |
106 | # TeamCity is a build add-in
107 | _TeamCity*
108 |
109 | # DotCover is a Code Coverage Tool
110 | *.dotCover
111 |
112 | # NCrunch
113 | _NCrunch_*
114 | .*crunch*.local.xml
115 | nCrunchTemp_*
116 |
117 | # MightyMoose
118 | *.mm.*
119 | AutoTest.Net/
120 |
121 | # Web workbench (sass)
122 | .sass-cache/
123 |
124 | # Installshield output folder
125 | [Ee]xpress/
126 |
127 | # DocProject is a documentation generator add-in
128 | DocProject/buildhelp/
129 | DocProject/Help/*.HxT
130 | DocProject/Help/*.HxC
131 | DocProject/Help/*.hhc
132 | DocProject/Help/*.hhk
133 | DocProject/Help/*.hhp
134 | DocProject/Help/Html2
135 | DocProject/Help/html
136 |
137 | # Click-Once directory
138 | publish/
139 |
140 | # Publish Web Output
141 | *.[Pp]ublish.xml
142 | *.azurePubxml
143 | # TODO: Comment the next line if you want to checkin your web deploy settings
144 | # but database connection strings (with potential passwords) will be unencrypted
145 | *.pubxml
146 | *.publishproj
147 |
148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
149 | # checkin your Azure Web App publish settings, but sensitive information contained
150 | # in these scripts will be unencrypted
151 | PublishScripts/
152 |
153 | # NuGet Packages
154 | *.nupkg
155 | # The packages folder can be ignored because of Package Restore
156 | **/packages/*
157 | # except build/, which is used as an MSBuild target.
158 | !**/packages/build/
159 | # Uncomment if necessary however generally it will be regenerated when needed
160 | #!**/packages/repositories.config
161 | # NuGet v3's project.json files produces more ignoreable files
162 | *.nuget.props
163 | *.nuget.targets
164 |
165 | # Microsoft Azure Build Output
166 | csx/
167 | *.build.csdef
168 |
169 | # Microsoft Azure Emulator
170 | ecf/
171 | rcf/
172 |
173 | # Windows Store app package directories and files
174 | AppPackages/
175 | BundleArtifacts/
176 | Package.StoreAssociation.xml
177 | _pkginfo.txt
178 |
179 | # Visual Studio cache files
180 | # files ending in .cache can be ignored
181 | *.[Cc]ache
182 | # but keep track of directories ending in .cache
183 | !*.[Cc]ache/
184 |
185 | # Others
186 | ClientBin/
187 | ~$*
188 | *~
189 | *.dbmdl
190 | *.dbproj.schemaview
191 | *.pfx
192 | *.publishsettings
193 | node_modules/
194 | orleans.codegen.cs
195 |
196 | # Since there are multiple workflows, uncomment next line to ignore bower_components
197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
198 | #bower_components/
199 |
200 | # RIA/Silverlight projects
201 | Generated_Code/
202 |
203 | # Backup & report files from converting an old project file
204 | # to a newer Visual Studio version. Backup files are not needed,
205 | # because we have git ;-)
206 | _UpgradeReport_Files/
207 | Backup*/
208 | UpgradeLog*.XML
209 | UpgradeLog*.htm
210 |
211 | # SQL Server files
212 | *.mdf
213 | *.ldf
214 |
215 | # Business Intelligence projects
216 | *.rdl.data
217 | *.bim.layout
218 | *.bim_*.settings
219 |
220 | # Microsoft Fakes
221 | FakesAssemblies/
222 |
223 | # GhostDoc plugin setting file
224 | *.GhostDoc.xml
225 |
226 | # Node.js Tools for Visual Studio
227 | .ntvs_analysis.dat
228 |
229 | # Visual Studio 6 build log
230 | *.plg
231 |
232 | # Visual Studio 6 workspace options file
233 | *.opt
234 |
235 | # Visual Studio LightSwitch build output
236 | **/*.HTMLClient/GeneratedArtifacts
237 | **/*.DesktopClient/GeneratedArtifacts
238 | **/*.DesktopClient/ModelManifest.xml
239 | **/*.Server/GeneratedArtifacts
240 | **/*.Server/ModelManifest.xml
241 | _Pvt_Extensions
242 |
243 | # Paket dependency manager
244 | .paket/paket.exe
245 | paket-files/
246 |
247 | # FAKE - F# Make
248 | .fake/
249 |
250 | # JetBrains Rider
251 | .idea/
252 | *.sln.iml
253 |
254 | # =========================
255 | # Operating System Files
256 | # =========================
257 |
258 | # OSX
259 | # =========================
260 |
261 | .DS_Store
262 | .AppleDouble
263 | .LSOverride
264 |
265 | # Thumbnails
266 | ._*
267 |
268 | # Files that might appear in the root of a volume
269 | .DocumentRevisions-V100
270 | .fseventsd
271 | .Spotlight-V100
272 | .TemporaryItems
273 | .Trashes
274 | .VolumeIcon.icns
275 |
276 | # Directories potentially created on remote AFP share
277 | .AppleDB
278 | .AppleDesktop
279 | Network Trash Folder
280 | Temporary Items
281 | .apdisk
282 |
283 | # Windows
284 | # =========================
285 |
286 | # Windows image file caches
287 | Thumbs.db
288 | ehthumbs.db
289 |
290 | # Folder config file
291 | Desktop.ini
292 |
293 | # Recycle Bin used on file shares
294 | $RECYCLE.BIN/
295 |
296 | # Windows Installer files
297 | *.cab
298 | *.msi
299 | *.msm
300 | *.msp
301 |
302 | # Windows shortcuts
303 | *.lnk
304 | /src/Test
305 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ..\obj
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://www.nuget.org/packages/SoxSharp)
2 | [](https://www.nuget.org/packages/SoxSharp)
3 | [](https://github.com/igece/SoxSharp/actions/workflows/build.yml)
4 |
5 | ## SoxSharp
6 |
7 | SoxSharp is a C# library that serves as a wrapper to [SoX - the Sound eXchange tool](http://sox.sourceforge.net/).
8 | SoX is a cross-platform (Windows, Linux, MacOS X, etc.) command line utility that can convert various formats of computer audio files in to other formats. It can also apply various effects to these sound files and play and record audio files on most platforms.
9 |
10 |
11 | ### How It Works
12 |
13 | #### Initial Setup
14 |
15 | When instantiating the **Sox** class, we pass to the constructor the location of the SoX executable to be used. Please note that, when SoX is executed, the directory of the application using the library will be used as the working directory, so any relative path included in both input and output files shall be relative to this directory.
16 |
17 |
18 | #### Get File Information
19 |
20 | Usage is pretty straightforward:
21 |
22 | ```cs
23 | using (var sox = new Sox("sox.exe"))
24 | {
25 | AudioInfo wavInfo = sox.GetInfo("test.wav");
26 | Console.WriteLine(wavInfo);
27 | }
28 | ```
29 |
30 | This is the same as executing `sox --info test.wav`. SoxSharp parses the SoX output and fills an **AudioInfo** instance with the retrieved information.
31 |
32 |
33 | #### File Conversion
34 |
35 | The simplest way to perform an audio conversion is to just call the **Sox.Process** method with both input and output files:
36 |
37 | ```cs
38 | using (var sox = new Sox("sox.exe"))
39 | {
40 | sox.Process("test.wav", "test.mp3");
41 | }
42 | ```
43 |
44 | The previous code will launch SoX with 'test.wav' as input file and 'test.mp3' as output file (the equivalent of executing SoX with the following parameters: `sox test.wav test.mp3`).
45 |
46 | To force the output to be encoded with MP3 format (instead of letting SoX to guess it from the output file extension) and use a sample rate of 32 KHz:
47 |
48 | ```cs
49 | using (var sox = new Sox("sox.exe"))
50 | {
51 | sox.Output.Type = FileType.MP3;
52 | sox.Output.SampleRate = 32000;
53 |
54 | sox.Process("test.wav", "test.mp3");
55 | }
56 | ```
57 |
58 | This is equivalent to call SoX with the following parameters: `sox test.wav --type mp3 --rate 32000 test.mp3`.
59 |
60 | SoX global options can be set through their respective properties in the **Sox** class. Format options to be applied to the output can be stablished through its respective properties in **Sox.Output**.
61 |
62 | Format options to be applied to the input are specified passing an **InputFile** instance to the **Sox.Process** method (instead of an input file string):
63 |
64 | ```cs
65 | using (var sox = new Sox("sox.exe"))
66 | {
67 | sox.Output.Type = FileType.MP3;
68 | sox.Output.SampleRate = 32000;
69 |
70 | InputFile testInput = new InputFile("test.wav");
71 | testInput.Volume = 0.8;
72 |
73 | sox.Process(testInput, "test.mp3");
74 | }
75 | ```
76 |
77 | This is equivalent to call SoX with the following parameters: `sox --volume 0.8 test.wav --type mp3 --rate 32000 test.mp3`.
78 |
79 |
80 | #### Applying Effects
81 |
82 | One or multiple effects can be added so they will applied to the output file:
83 |
84 | ```cs
85 | using (var sox = new Sox("sox.exe"))
86 | {
87 | sox.Output.Type = FileType.MP3;
88 | sox.Effects.Add(new VolumeEffect(10, GainType.Db));
89 | sox.Effects.Add(new HighPassFilterEffect(500));
90 |
91 | sox.Process("test.wav", "test.mp3");
92 | }
93 | ```
94 |
95 | Currently not all SoX effects have been implemented into SoxSharp. To see which effects are supported, please read [this issue](https://github.com/igece/SoxSharp/issues/1).
96 |
97 |
98 | #### Playing and Recording
99 |
100 | To record audio from the default audio device, use the **Sox.Record** method specifying the output file name:
101 |
102 | ```cs
103 | sox.Record("test_record.mp3");
104 | ```
105 |
106 | Analogously, **Sox.Play** allows to send an input file to the default audio device. In this case, the input file can be expressed as an file name string or a **InputFile** instance.
107 |
108 | The same results can be obtained if calling **Sox.Process** using `--default-device` as output (for playing) or input (for recording) file.
109 |
110 |
111 | #### Error Handling
112 |
113 | If any requested SoX operation is unable to be processed, either because SoX process can't be launched or beacuse it generates an error, a **SoxException** with details about the error will be thrown.
114 |
115 |
116 | #### Events
117 |
118 | You can subscribe to receive any log message generated by SoX through the **OnLogMessage** event. Please note that log messages of type FAIL will not be reported through this event but as exceptions, as stated in [Error Handling](#error-handling).
119 |
120 | ```cs
121 | // Subscribe to OnLogMessage.
122 | sox.OnLogMessage += sox_OnLogMessage;
123 |
124 | void sox_OnLogMessage(object sender, LogMessageEventArgs e)
125 | {
126 | Console.WriteLine(e.LogLevel + ": " + e.Message);
127 | }
128 | ```
129 |
130 | Also, while executing a **Process** call you can obtain updated progress information about the operation subscribing to the **OnProgress** event:
131 |
132 | ```cs
133 | // Subscribe to OnProgress event before calling Process method.
134 | sox.OnProgress += sox_OnProgress;
135 |
136 | void sox_OnProgress(object sender, ProgressEventArgs e)
137 | {
138 | Console.WriteLine("{0} ({1}% completed)", e.Processed.ToString(@"hh\:mm\:ss\.ff"), e.Progress);
139 | }
140 | ```
141 |
142 |
143 | ### Concurrency
144 |
145 | All the work is done in the calling thread. Each **Sox** class instance can handle only one process at the same time, and will block the calling thread until finished. You are responsible for creating any worker thread if needed.
146 |
147 | The library provides two different methods to cancel any work that is in progress:
148 |
149 | * Calling the **Abort()** method of the **Sox** class.
150 |
151 | * Inside the **OnProgress** event handler. **ProgressEventArgs** provides a boolean **Abort** member that can be set to **true** to end the current work.
152 |
153 |
154 | ### Library Reference
155 |
156 | A detailed description of all components of the library is available at the [repository wiki](https://github.com/igece/SoxSharp/wiki/Reference-Guide).
157 |
158 |
159 |
--------------------------------------------------------------------------------
/src/AudioInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 |
5 | namespace SoxSharp
6 | {
7 | ///
8 | /// Provides information about an audio file.
9 | ///
10 | public struct AudioInfo
11 | {
12 | ///
13 | /// Number of audio channels.
14 | ///
15 | public readonly UInt16 Channels;
16 |
17 | ///
18 | /// Audio sample rate.
19 | ///
20 | public readonly UInt32 SampleRate;
21 |
22 | ///
23 | /// Audio sample size (bits).
24 | ///
25 | public readonly UInt16 SampleSize;
26 |
27 | ///
28 | /// Audio time length.
29 | ///
30 | public readonly TimeSpan Duration;
31 |
32 | ///
33 | /// Audio file size.
34 | ///
35 | public readonly UInt64 Size;
36 |
37 | ///
38 | /// Audio bitrate.
39 | ///
40 | public readonly UInt32 BitRate;
41 |
42 | ///
43 | /// Audio format.
44 | ///
45 | public readonly string Format;
46 |
47 |
48 | ///
49 | /// Initializes a new instance of the class.
50 | ///
51 | /// Number of audio channels.
52 | /// Audio sample rate.
53 | /// Audio sample size (bits).
54 | /// Audio time length.
55 | /// Audio file size
56 | ///
57 | /// Audio format.
58 | public AudioInfo(UInt16 channels, UInt32 sampleRate, UInt16 sampleSize, TimeSpan duration, UInt64 size, UInt32 bitRate, string format)
59 | {
60 | Channels = channels;
61 | SampleRate = sampleRate;
62 | SampleSize = sampleSize;
63 | Duration = duration;
64 | Size = size;
65 | BitRate = bitRate;
66 | Format = format;
67 | }
68 |
69 |
70 | ///
71 | /// Returns information about the instance (invalidates ).
72 | ///
73 | /// String containing all instance properties values.
74 | public override string ToString()
75 | {
76 | StringBuilder result = new StringBuilder();
77 |
78 | result.AppendLine("Channels: " + Channels);
79 | result.AppendLine("Sample Rate: " + SampleRate);
80 | result.AppendLine("Sample Size: " + SampleSize);
81 | result.AppendLine("Duration: " + Duration.ToString(@"hh\:mm\:ss\.ff"));
82 | result.AppendLine("Size: " + Size);
83 | result.AppendLine("BitRate: " + BitRate);
84 | result.AppendLine("Format: " + Format);
85 |
86 | return result.ToString();
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/Effects/AllPassFilterEffect.cs:
--------------------------------------------------------------------------------
1 | using SoxSharp.Effects.Types;
2 | using System.Collections.Generic;
3 |
4 |
5 | namespace SoxSharp.Effects
6 | {
7 | ///
8 | /// Apply a two-pole all-pass filter with a central frequency and width. An all-pass filter changes the audio’s
9 | /// frequency to phase relationship without changing its frequency to amplitude relationship.
10 | ///
11 | public class AllPassFilterEffect : BaseEffect
12 | {
13 | ///
14 | /// SoX effect name.
15 | ///
16 | public override string Name { get { return "allpass"; } }
17 |
18 | ///
19 | /// Central frequency.
20 | ///
21 | public Frequency Frequency { get; set; }
22 |
23 | ///
24 | /// Filter width.
25 | ///
26 | public Width Width { get; set; }
27 |
28 |
29 | ///
30 | /// Initializes a new instance of the class.
31 | ///
32 | /// Central frequency.
33 | /// Filter width.
34 | public AllPassFilterEffect(double frequency, double width)
35 | {
36 | Frequency = frequency;
37 | Width = width;
38 | }
39 |
40 |
41 | ///
42 | /// Initializes a new instance of the class.
43 | ///
44 | /// Central frequency.
45 | /// Filter width.
46 | public AllPassFilterEffect(Frequency frequency, Width width)
47 | {
48 | Frequency = frequency;
49 | Width = width;
50 | }
51 |
52 |
53 | ///
54 | /// Translate an instance to a set of command arguments to be passed to SoX.
55 | /// (invalidates ).
56 | ///
57 | /// A containing SoX command arguments to apply an All-Pass Filter
58 | /// effect.
59 | public override string ToString()
60 | {
61 | List effectArgs = new List(3) { Name };
62 |
63 | effectArgs.Add(Frequency.ToString());
64 | effectArgs.Add(Width.ToString());
65 |
66 | return string.Join(" ", effectArgs);
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/Effects/BandPassFilterEffect.cs:
--------------------------------------------------------------------------------
1 | using SoxSharp.Effects.Types;
2 | using System.Collections.Generic;
3 |
4 |
5 | namespace SoxSharp.Effects
6 | {
7 | ///
8 | /// Apply a two-pole Butterworth band-pass filter with a central frequency and a (3dB-point) bandwidth.
9 | /// The filter roll off at 6dB per octave (20dB per decade).
10 | ///
11 | public class BandPassFilterEffect : BaseEffect
12 | {
13 | ///
14 | /// SoX effect name.
15 | ///
16 | public override string Name { get { return "bandpass"; } }
17 |
18 | ///
19 | /// Central frequency.
20 | ///
21 | public Frequency Frequency { get; set; }
22 |
23 | ///
24 | /// Filter width.
25 | ///
26 | public Width Width { get; set; }
27 |
28 | ///
29 | /// Selects a constant skirt gain (peak gain = Q) instead of the default constant 0dB peak gain.
30 | ///
31 | public bool? SkirtGain { get; set; }
32 |
33 |
34 | ///
35 | ///
36 | ///
37 | /// Central frequency.
38 | /// Filter width.
39 | public BandPassFilterEffect(double frequency, double width)
40 | {
41 | Frequency = frequency;
42 | Width = width;
43 | }
44 |
45 |
46 | ///
47 | ///
48 | ///
49 | /// Central frequency.
50 | /// Filter width.
51 | public BandPassFilterEffect(Frequency frequency, Width width)
52 | {
53 | Frequency = frequency;
54 | Width = width;
55 | }
56 |
57 |
58 | ///
59 | /// Translate an instance to a set of command arguments to be passed to SoX.
60 | /// (invalidates ).
61 | ///
62 | /// A containing SoX command arguments to apply an Band-Pass Filter effect.
63 | public override string ToString()
64 | {
65 | List effectArgs = new List(4) { Name };
66 |
67 | if (SkirtGain.HasValue && (SkirtGain.Value == true))
68 | effectArgs.Add("-c");
69 |
70 | effectArgs.Add(Frequency.ToString());
71 | effectArgs.Add(Width.ToString());
72 |
73 | return string.Join(" ", effectArgs);
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/Effects/BandRejectFilterEffect.cs:
--------------------------------------------------------------------------------
1 | using SoxSharp.Effects.Types;
2 | using System.Collections.Generic;
3 |
4 |
5 | namespace SoxSharp.Effects
6 | {
7 | ///
8 | /// Apply a two-pole Butterworth band-reject filter with a central frequency and a (3dB-point) bandwidth.
9 | /// The filter roll off at 6dB per octave (20dB per decade).
10 | ///
11 | public class BandRejectFilterEffect : BaseEffect
12 | {
13 | ///
14 | /// SoX effect name.
15 | ///
16 | public override string Name { get { return "bandreject"; } }
17 |
18 | ///
19 | /// Central frequency.
20 | ///
21 | public Frequency Frequency { get; set; }
22 |
23 | ///
24 | /// Filter width.
25 | ///
26 | public Width Width { get; set; }
27 |
28 |
29 | ///
30 | /// Initializes a new instance of the class.
31 | ///
32 | /// Central frequency.
33 | /// Filter width.
34 | public BandRejectFilterEffect(double frequency, double width)
35 | {
36 | Frequency = frequency;
37 | Width = width;
38 | }
39 |
40 |
41 | ///
42 | /// Initializes a new instance of the class.
43 | ///
44 | /// Central frequency.
45 | /// Filter width.
46 | public BandRejectFilterEffect(Frequency frequency, Width width)
47 | {
48 | Frequency = frequency;
49 | Width = width;
50 | }
51 |
52 |
53 | ///
54 | /// Translate a instance to a set of command arguments to be passed to SoX.
55 | /// (invalidates ).
56 | ///
57 | /// A containing SoX command arguments to apply a Band-Reject Filter effect.
58 | public override string ToString()
59 | {
60 | List effectArgs = new List(3) { Name };
61 |
62 | effectArgs.Add(Frequency.ToString());
63 | effectArgs.Add(Width.ToString());
64 |
65 | return string.Join(" ", effectArgs);
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/src/Effects/BaseEffect.cs:
--------------------------------------------------------------------------------
1 | namespace SoxSharp.Effects
2 | {
3 | public abstract class BaseEffect : IBaseEffect
4 | {
5 | ///
6 | /// SoX effect name.
7 | ///
8 | public abstract string Name { get; }
9 |
10 | ///
11 | /// Translate an effect class instance to a set of command arguments to be passed to SoX.
12 | /// (invalidates ).
13 | ///
14 | /// A containing SoX command arguments to apply the effect.
15 | public abstract override string ToString();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Effects/BassEffect.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using SoxSharp.Effects.Types;
3 |
4 |
5 | namespace SoxSharp.Effects
6 | {
7 | ///
8 | /// Boost or cut the bass (lower) frequencies of the audio using a two-pole shelving filter with a response
9 | /// similar to that of a standard hi-fi’s tone-controls. This is also known as shelving equalisation (EQ).
10 | ///
11 | public class BassEffect : BaseEffect
12 | {
13 | ///
14 | /// SoX effect name.
15 | ///
16 | public override string Name { get { return "bass"; } }
17 |
18 | ///
19 | /// Gives the gain at 0 Hz. Its useful range is about −20 (for a large cut) to +20 (for a large boost).
20 | /// Beware of Clipping when using a positive gain.
21 | ///
22 | public double Gain { get; set; }
23 |
24 | ///
25 | /// Sets the filter’s central frequency and so can be used to extend or reduce the frequency range to
26 | /// be boosted or cut. The default value is 100 Hz.
27 | ///
28 | public Frequency? Frequency { get; set; }
29 |
30 | ///
31 | /// Determines how steep is the filter’s shelf transition. In addition to the common width specification methods,
32 | /// ‘slope’ (the default) may be used. The useful range of ‘slope’ is about 0.3, for a gentle slope, to 1
33 | /// (the maximum), for a steep slope; the default value is 0.5.
34 | ///
35 | public Width? Width { get; set; }
36 |
37 |
38 | public BassEffect(double gain)
39 | {
40 | Gain = gain;
41 | }
42 |
43 |
44 | public BassEffect(double gain, double frequency)
45 | : this(gain)
46 | {
47 | Frequency = frequency;
48 | }
49 |
50 |
51 | public BassEffect(double gain, double frequency, double width)
52 | : this(gain, frequency)
53 | {
54 | Width = width;
55 | }
56 |
57 |
58 | public BassEffect(double gain, Frequency frequency)
59 | : this(gain)
60 | {
61 | Frequency = frequency;
62 | }
63 |
64 |
65 | public BassEffect(double gain, Frequency frequency, Width width)
66 | : this(gain, frequency)
67 | {
68 | Width = width;
69 | }
70 |
71 | ///
72 | /// Translate a instance to a set of command arguments to be passed to SoX.
73 | /// (invalidates ).
74 | ///
75 | /// A containing SoX command arguments to apply a Bass effect.
76 | public override string ToString()
77 | {
78 | List effectArgs = new List(4) { Name };
79 |
80 | effectArgs.Add(Gain.ToString());
81 |
82 | if (Frequency.HasValue)
83 | effectArgs.Add(Frequency.Value.ToString());
84 |
85 | if (Width.HasValue)
86 | effectArgs.Add(Width.Value.ToString());
87 |
88 | return string.Join(" ", effectArgs);
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/Effects/ContrastEffect.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Globalization;
3 |
4 | namespace SoxSharp.Effects
5 | {
6 | ///
7 | /// Comparable with compression, this effect modifies an audio signal to make it sound louder.
8 | ///
9 | public class ContrastEffect : BaseEffect
10 | {
11 | ///
12 | /// SoX effect name.
13 | ///
14 | public override string Name { get { return "contrast"; } }
15 |
16 | ///
17 | /// Controls the amount of the enhancement and is a number in the range 0−100 (default 75). Note that a value of 0
18 | /// still gives a significant contrast enhancement.
19 | ///
20 | public double Enhancement { get; set; }
21 |
22 |
23 | public ContrastEffect(double enhancement)
24 | {
25 | Enhancement = enhancement;
26 | }
27 |
28 |
29 | ///
30 | /// Translate a instance to a set of command arguments to be passed to SoX.
31 | /// (invalidates ).
32 | ///
33 | /// A containing SoX command arguments to apply a Contrast effect.
34 | public override string ToString()
35 | {
36 | List effectArgs = new List(2) { Name };
37 | effectArgs.Add(Enhancement.ToString(CultureInfo.InvariantCulture));
38 |
39 | return string.Join(" ", effectArgs);
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Effects/HighPassFilterEffect.cs:
--------------------------------------------------------------------------------
1 | using SoxSharp.Effects.Types;
2 | using System.Collections.Generic;
3 |
4 |
5 | namespace SoxSharp.Effects
6 | {
7 | ///
8 | /// Apply a high-pass filter with 3dB point frequency. The filter can be either single-pole or double-pole
9 | /// (the default). The filter roll off at 6dB per pole per octave (20dB per pole per decade).
10 | ///
11 | public class HighPassFilterEffect : BaseEffect
12 | {
13 | ///
14 | /// SoX effect name.
15 | ///
16 | public override string Name { get { return "highpass"; } }
17 |
18 | ///
19 | /// Filter type (single-pole or double-pole).
20 | ///
21 | public FilterType? Type { get; set; }
22 |
23 | ///
24 | /// Central frequency.
25 | ///
26 | public Frequency Frequency { get; set; }
27 |
28 | ///
29 | /// Filter width. Applies only to double-pole filter; the default is Q = 0.707 and gives a Butterworth response.
30 | ///
31 | public Width? Width { get; set; }
32 |
33 |
34 | ///
35 | /// Initializes a new instance of the class.
36 | ///
37 | /// Central frequency.
38 | public HighPassFilterEffect(double frequency)
39 | {
40 | Frequency = frequency;
41 | }
42 |
43 |
44 | ///
45 | /// Initializes a new instance of the class.
46 | ///
47 | /// Central frequency.
48 | /// Filter width.
49 | public HighPassFilterEffect(double frequency, double width)
50 | : this(frequency)
51 | {
52 | Width = width;
53 | }
54 |
55 |
56 | ///
57 | /// Initializes a new instance of the class.
58 | ///
59 | /// Central frequency.
60 | public HighPassFilterEffect(Frequency frequency)
61 | {
62 | Frequency = frequency;
63 | }
64 |
65 |
66 | ///
67 | /// Initializes a new instance of the class.
68 | ///
69 | /// Central frequency.
70 | /// Filter width.
71 | public HighPassFilterEffect(Frequency frequency, Width width)
72 | : this(frequency)
73 | {
74 | Width = width;
75 | }
76 |
77 |
78 | ///
79 | /// Translate a instance to a set of command arguments to be passed to SoX.
80 | /// (invalidates ).
81 | ///
82 | /// A containing SoX command arguments to apply a High-Pass Filter effect.
83 | public override string ToString()
84 | {
85 | List effectArgs = new List(4) { Name };
86 |
87 | if (Type.HasValue)
88 | {
89 | switch (Type.Value)
90 | {
91 | case FilterType.SinglePole:
92 |
93 | effectArgs.Add("-1");
94 | break;
95 |
96 | case FilterType.DoublePole:
97 |
98 | effectArgs.Add("-2");
99 | break;
100 |
101 | default:
102 |
103 | // Do nothing;
104 | break;
105 | }
106 | }
107 |
108 | effectArgs.Add(Frequency.ToString());
109 |
110 | if (Width.HasValue)
111 | effectArgs.Add(Width.Value.ToString());
112 |
113 | return string.Join(" ", effectArgs);
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/Effects/IBaseEffect.cs:
--------------------------------------------------------------------------------
1 | namespace SoxSharp.Effects
2 | {
3 | public interface IBaseEffect
4 | {
5 | ///
6 | /// SoX effect name.
7 | ///
8 | string Name { get; }
9 |
10 | ///
11 | /// Translate an effect class instance to a set of command arguments to be passed to SoX.
12 | /// (invalidates ).
13 | ///
14 | /// A containing SoX command arguments to apply the effect.
15 | string ToString();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Effects/LoudnessEffect.cs:
--------------------------------------------------------------------------------
1 | using SoxSharp.Exceptions;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 |
5 | namespace SoxSharp.Effects
6 | {
7 | ///
8 | /// Loudness control. Similar to the gain effect, but provides equalisation for the human auditory system. See
9 | /// http://en.wikipedia.org/wiki/Loudness for a detailed description of loudness. The gain adjustment is usually
10 | /// negative and the signal is equalised according to ISO 226 w.r.t. a reference level of 65dB. An alternative
11 | /// reference level may be given if the original audio has been equalised for some other optimal level.
12 | ///
13 | public class LoudnessEffect : BaseEffect
14 | {
15 | ///
16 | /// SoX effect name.
17 | ///
18 | public override string Name { get { return "loudness"; } }
19 |
20 | ///
21 | /// Gain adjustment. A default gain of −10dB is used if no value is given.
22 | ///
23 | public double? Gain { get; set; }
24 |
25 | ///
26 | /// Alternative reference level to use.
27 | ///
28 | public double? Reference { get; set; }
29 |
30 |
31 | ///
32 | /// Initializes a new instance of the class.
33 | ///
34 | public LoudnessEffect()
35 | {
36 | }
37 |
38 | ///
39 | /// Initializes a new instance of the class.
40 | ///
41 | /// Volume gain.
42 | public LoudnessEffect(double gain)
43 | {
44 | Gain = gain;
45 | }
46 |
47 |
48 | ///
49 | /// Initializes a new instance of the class.
50 | ///
51 | /// Volume gain.
52 | /// How to interpret the gain value.
53 | public LoudnessEffect(double gain, double reference)
54 | : this(gain)
55 | {
56 | Reference = reference;
57 | }
58 |
59 |
60 | ///
61 | /// Translate a instance to a set of command arguments to be passed to SoX to be applied
62 | /// to the input file (invalidates ).
63 | ///
64 | /// A containing SoX command arguments to apply a Loudness effect.
65 | public override string ToString()
66 | {
67 | if (Reference.HasValue && !Gain.HasValue)
68 | throw new SoxEffectException(Name, "Reference value set without specifying a Gain value.");
69 |
70 | List effectArgs = new List(3) { Name };
71 |
72 | if (Gain.HasValue)
73 | effectArgs.Add(Gain.Value.ToString(CultureInfo.InvariantCulture));
74 |
75 | if (Reference.HasValue)
76 | effectArgs.Add(Reference.Value.ToString(CultureInfo.InvariantCulture));
77 |
78 | return string.Join(" ", effectArgs);
79 | }
80 | }
81 | }
82 |
83 |
--------------------------------------------------------------------------------
/src/Effects/LowPassFilterEffect.cs:
--------------------------------------------------------------------------------
1 | using SoxSharp.Effects.Types;
2 | using System.Collections.Generic;
3 |
4 |
5 | namespace SoxSharp.Effects
6 | {
7 | ///
8 | /// Apply a low-pass filter with 3dB point frequency. The filter can be either single-pole or double-pole
9 | /// (the default). The filter roll off at 6dB per pole per octave (20dB per pole per decade).
10 | ///
11 | public class LowPassFilterEffect : BaseEffect
12 | {
13 | ///
14 | /// SoX effect name.
15 | ///
16 | public override string Name { get { return "lowpass"; } }
17 |
18 | public FilterType? Type { get; set; }
19 |
20 | public Frequency Frequency { get; set; }
21 |
22 | ///
23 | /// Applies only to double-pole filter; the default is Q = 0.707 and gives a Butterworth response.
24 | ///
25 | public Width? Width { get; set; }
26 |
27 |
28 | ///
29 | /// Initializes a new instance of the class.
30 | ///
31 | public LowPassFilterEffect(double frequency)
32 | {
33 | Frequency = frequency;
34 | }
35 |
36 |
37 | ///
38 | /// Initializes a new instance of the class.
39 | ///
40 | public LowPassFilterEffect(double frequency, double width)
41 | : this(frequency)
42 | {
43 | Width = width;
44 | }
45 |
46 |
47 | public LowPassFilterEffect(Frequency frequency)
48 | {
49 | Frequency = frequency;
50 | }
51 |
52 |
53 | public LowPassFilterEffect(Frequency frequency, Width width)
54 | : this(frequency)
55 | {
56 | Width = width;
57 | }
58 |
59 |
60 | ///
61 | /// Translate a instance to a set of command arguments to be passed to SoX.
62 | /// (invalidates ).
63 | ///
64 | /// A containing SoX command arguments to apply a Low-Pass Filter effect.
65 | public override string ToString()
66 | {
67 | List effectArgs = new List(3) { Name };
68 |
69 | if (Type.HasValue)
70 | {
71 | switch (Type.Value)
72 | {
73 | case FilterType.SinglePole:
74 |
75 | effectArgs.Add("-1");
76 | break;
77 |
78 | case FilterType.DoublePole:
79 |
80 | effectArgs.Add("-2");
81 | break;
82 |
83 | default:
84 |
85 | // Do nothing.
86 | break;
87 | }
88 | }
89 |
90 | effectArgs.Add(Frequency.ToString());
91 |
92 | if (Width.HasValue)
93 | effectArgs.Add(Width.Value.ToString());
94 |
95 | return string.Join(" ", effectArgs);
96 | }
97 | }
98 | }
--------------------------------------------------------------------------------
/src/Effects/NoiseProfileEffect.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 |
4 | namespace SoxSharp.Effects
5 | {
6 | ///
7 | /// Calculate a profile of the audio for use in noise reduction and save it to file. This effect is usually run on a
8 | /// section of audio (obtained adding a effect to the process chain) that
9 | /// ideally would contain silence but in fact contains noise. Such sections are typically found at the beginning or
10 | /// the end of a recording.
11 | ///
12 | public class NoiseProfileEffect : BaseEffect
13 | {
14 | ///
15 | /// SoX effect name.
16 | ///
17 | public override string Name { get { return "noiseprof"; } }
18 |
19 | public string File { get; set; }
20 |
21 |
22 | ///
23 | /// Initializes a new instance of the class.
24 | ///
25 | /// File.
26 | public NoiseProfileEffect(string file)
27 | {
28 | File = file;
29 | }
30 |
31 |
32 | ///
33 | /// Translate a instance to a set of command arguments to be passed to SoX to be applied to the input file (invalidates ).
34 | ///
35 | /// A containing SoX command arguments to apply a Noise Profile effect.
36 | public override string ToString()
37 | {
38 | List effectArgs = new List(2) { Name };
39 | effectArgs.Add(File);
40 |
41 | return string.Join(" ", effectArgs);
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Effects/NoiseReductionEffect.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Globalization;
3 |
4 | namespace SoxSharp.Effects
5 | {
6 | ///
7 | /// Reduce noise in the audio signal by profiling and filtering. This effect is moderately effective at removing
8 | /// consistent background noise such as hiss or hum. Previous to use this effect, a noise profile of the file should
9 | /// be obatined using .
10 | ///
11 | public class NoiseReductionEffect : BaseEffect
12 | {
13 | ///
14 | /// SoX effect name.
15 | ///
16 | public override string Name { get { return "noisered"; } }
17 |
18 | public string File { get; set; }
19 |
20 | ///
21 | /// How much noise should be removed. Valid values are between 0 and 1, with a default of 0.5. Higher numbers will
22 | /// remove more noise but present a greater likelihood of removing wanted components of the audio signal.
23 | ///
24 | public double? Amount { get; set; }
25 |
26 |
27 | public NoiseReductionEffect(string profile)
28 | {
29 | File = profile;
30 | }
31 |
32 |
33 | public NoiseReductionEffect(string profile, double amount)
34 | : this(profile)
35 | {
36 | Amount = amount;
37 | }
38 |
39 |
40 | ///
41 | /// Translate a instance to a set of command arguments to be passed to SoX.
42 | /// (invalidates ).
43 | ///
44 | /// A containing SoX command arguments to apply a Noise Reduction effect.
45 | public override string ToString()
46 | {
47 | List effectArgs = new List(3) { Name };
48 | effectArgs.Add(File);
49 |
50 | if (Amount.HasValue)
51 | effectArgs.Add(Amount.Value.ToString(CultureInfo.InvariantCulture));
52 |
53 | return string.Join(" ", effectArgs);
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/Effects/ReverseEffect.cs:
--------------------------------------------------------------------------------
1 | namespace SoxSharp.Effects
2 | {
3 | ///
4 | /// Reverse the audio completely. Requires temporary file space to store the audio to be reversed.
5 | ///
6 | public class ReverseEffect : BaseEffect
7 | {
8 | ///
9 | /// SoX effect name.
10 | ///
11 | public override string Name { get { return "reverse"; } }
12 |
13 |
14 | ///
15 | /// Translate a instance to a set of command arguments to be passed to SoX.
16 | /// (invalidates ).
17 | ///
18 | /// A containing SoX command arguments to apply a Reverse effect.
19 | public override string ToString()
20 | {
21 | return Name;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Effects/SpeedEffect.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using System.Text;
3 |
4 |
5 | namespace SoxSharp.Effects
6 | {
7 | ///
8 | /// Adjust the audio speed (pitch and tempo together). Technically, the speed effect only changes the sample rate
9 | /// information, leaving the samples themselves untouched. The rate effect is invoked automatically to resample to
10 | /// the output sample rate, using its default quality/speed. For higher quality or higher speed resampling, in
11 | /// addition to the speed effect, specify the rate effect with the desired quality option.
12 | ///
13 | public class SpeedEffect : BaseEffect
14 | {
15 | ///
16 | /// SoX effect name.
17 | ///
18 | public override string Name { get { return "speed"; } }
19 |
20 | ///
21 | /// The ratio of the new speed to the old speed: greater than 1 speeds up, less than 1 slows down.
22 | ///
23 | public double Factor { get; set; }
24 |
25 | ///
26 | /// Interpret Factor as number of cents (i.e. 100ths of a semitone) by which the pitch (and tempo) should be
27 | /// adjusted: greater than 0 increases, less than 0 decreases.
28 | ///
29 | public bool? AsCents { get; set; }
30 |
31 |
32 | public SpeedEffect(double factor)
33 | {
34 | Factor = factor;
35 | }
36 |
37 |
38 | public SpeedEffect(double factor, bool asCents)
39 | : this(factor)
40 | {
41 | AsCents = asCents;
42 | }
43 |
44 |
45 | ///
46 | /// Translate a instance to a set of command arguments to be passed to SoX.
47 | /// (invalidates ).
48 | ///
49 | /// A containing SoX command arguments to apply a Speed effect.
50 | public override string ToString()
51 | {
52 | StringBuilder effectArgs = new StringBuilder(Name);
53 | effectArgs.Append(" " + Factor.ToString(CultureInfo.InvariantCulture));
54 |
55 | if (AsCents.HasValue && (AsCents.Value == true))
56 | effectArgs.Append("c");
57 |
58 | return effectArgs.ToString();
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Effects/TempoEffect.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Globalization;
3 | using SoxSharp.Effects.Types;
4 | using SoxSharp.Exceptions;
5 |
6 |
7 | namespace SoxSharp.Effects
8 | {
9 | ///
10 | /// Change the audio playback speed but not its pitch.
11 | /// This effect uses the WSOLA algorithm. The audio is chopped up into segments which are then shifted in
12 | /// the time domain and overlapped (cross-faded) at points where their waveforms are most similar as
13 | /// determined by measurement of ‘least squares’.
14 | ///
15 | public class TempoEffect: BaseEffect
16 | {
17 | ///
18 | /// SoX effect name.
19 | ///
20 | public override string Name { get { return "tempo"; } }
21 |
22 | ///
23 | /// Ratio of new tempo to the old tempo.
24 | /// A value of 1.1 speeds up the tempo by 10%, 0.9 slows it down by 10%.
25 | ///
26 | public double Factor { get; set; }
27 |
28 | ///
29 | /// Use tree searches instead of linear searches to find the best overlapping points.
30 | /// This makes the effect work more quickly, but the result may not sound as good.
31 | /// However, if you must improve the processing speed, this generally reduces the sound
32 | /// quality less than reducing the search or overlap values.
33 | ///
34 | public bool? UseTreeSearches;
35 |
36 | ///
37 | /// Calculates default value of Segment based on factor, and default Search and Overlap values based on Segment.
38 | ///
39 | public OptimizationType? Optimization;
40 |
41 | ///
42 | /// Algorithm’s segment size in milliseconds.
43 | /// If no other flags are specified, the default value is 82 and is typically suited to making small changes to the tempo of music.
44 | /// For larger changes (e.g. a factor of 2), 41 ms may give a better result.
45 | ///
46 | public double? Segment { get; set; }
47 |
48 | ///
49 | /// Audio length in milliseconds over which the algorithm will search for overlapping points.
50 | /// If no other flags are specified, the default value is 14.68. Larger values use more processing time and may or may not produce better results.
51 | /// A practical maximum is half the value of segment. Search can be reduced to cut processing time at the risk of degrading output quality.
52 | /// The −m, −s, and −l flags will cause the search default to be automatically adjusted based on segment.
53 | ///
54 | public double? Search { get; set; }
55 |
56 | ///
57 | /// Segment overlap length in milliseconds.
58 | /// Default value is 12 but −m, −s, or −l flags automatically adjust overlap based on segment size.
59 | /// Increasing overlap increases processing time and may increase quality. A practical maximum for overlap
60 | /// is the value of search, with overlap typically being (at least) a little smaller than search.
61 | ///
62 | public double? Overlap { get; set; }
63 |
64 |
65 | ///
66 | /// Initializes a new instance of the class.
67 | ///
68 | /// Ratio of new tempo to the old tempo.
69 | public TempoEffect(double factor)
70 | {
71 | Factor = factor;
72 | }
73 |
74 |
75 | ///
76 | /// Initializes a new instance of the class.
77 | ///
78 | /// Ratio of new tempo to the old tempo.
79 | /// Algorithm’s segment size in milliseconds.
80 | public TempoEffect(double factor, double segment)
81 | : this (factor)
82 | {
83 | Segment = segment;
84 | }
85 |
86 |
87 | ///
88 | /// Initializes a new instance of the class.
89 | ///
90 | /// Ratio of new tempo to the old tempo.
91 | /// Algorithm’s segment size in milliseconds.
92 | /// Audio length in milliseconds over which the algorithm will search for overlapping points.
93 | public TempoEffect(double factor, double segment, double search)
94 | : this(factor, segment)
95 | {
96 | Search = search;
97 | }
98 |
99 |
100 | ///
101 | /// Initializes a new instance of the class.
102 | ///
103 | /// Ratio of new tempo to the old tempo.
104 | /// Algorithm’s segment size in milliseconds.
105 | /// Audio length in milliseconds over which the algorithm will search for overlapping points.
106 | /// Segment overlap length in milliseconds.
107 | public TempoEffect(double factor, double segment, double search, double overlap)
108 | : this(factor, segment, search)
109 | {
110 | Overlap = overlap;
111 | }
112 |
113 |
114 | ///
115 | /// Translate a instance to a set of command arguments to be passed to SoX.
116 | /// (invalidates ).
117 | ///
118 | /// A containing SoX command arguments to apply a Tempo effect.
119 | public override string ToString()
120 | {
121 | if (Search.HasValue && !Segment.HasValue)
122 | throw new SoxEffectException(Name, "Search value set without specifying a Segment value.");
123 |
124 | if (Overlap.HasValue && (!Search.HasValue || !Segment.HasValue))
125 | throw new SoxEffectException(Name, "Overlap value set without specifying Segment and Search values.");
126 |
127 | List effectArgs = new List(6) { Name };
128 |
129 | if (UseTreeSearches.HasValue)
130 | effectArgs.Add("-q");
131 |
132 | if (Optimization.HasValue)
133 | {
134 | switch (Optimization.Value)
135 | {
136 | case OptimizationType.Music:
137 |
138 | effectArgs.Add("-m");
139 | break;
140 |
141 | case OptimizationType.Speech:
142 |
143 | effectArgs.Add("-s");
144 | break;
145 |
146 | case OptimizationType.LinearProcessing:
147 |
148 | effectArgs.Add("-l");
149 | break;
150 |
151 | default:
152 |
153 | // Do nothing.
154 | break;
155 | }
156 | }
157 |
158 | effectArgs.Add(Factor.ToString(CultureInfo.InvariantCulture));
159 |
160 | if (Segment.HasValue)
161 | effectArgs.Add(Segment.Value.ToString(CultureInfo.InvariantCulture));
162 |
163 | if (Search.HasValue)
164 | effectArgs.Add(Search.Value.ToString(CultureInfo.InvariantCulture));
165 |
166 | if (Overlap.HasValue)
167 | effectArgs.Add(Overlap.Value.ToString(CultureInfo.InvariantCulture));
168 |
169 | return string.Join(" ", effectArgs);
170 | }
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/src/Effects/TrebleEffect.cs:
--------------------------------------------------------------------------------
1 | using SoxSharp.Effects.Types;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 |
5 | namespace SoxSharp.Effects
6 | {
7 | ///
8 | /// Boost or cut the treble (upper) frequencies of the audio using a two-pole shelving filter with a response similar
9 | /// to that of a standard hi-fi’s tone-controls. This is also known as shelving equalisation (EQ).
10 | ///
11 | public class TrebleEffect : BaseEffect
12 | {
13 | ///
14 | /// SoX effect name.
15 | ///
16 | public override string Name { get { return "treble"; } }
17 |
18 | ///
19 | /// Gives the gain at whichever is the lower of ∼22 kHz and the Nyquist frequency. Its useful range is about −20
20 | /// (for a large cut) to +20 (for a large boost). Beware of Clipping when using a positive gain.
21 | ///
22 | public double Gain { get; set; }
23 |
24 | ///
25 | /// Sets the filter’s central frequency and so can be used to extend or reduce the frequency range to
26 | /// be boosted or cut. The default value is 3 kHz.
27 | ///
28 | public Frequency? Frequency { get; set; }
29 |
30 | ///
31 | /// Determines how steep is the filter’s shelf transition. In addition to the common width specification methods,
32 | /// ‘slope’ (the default) may be used. The useful range of ‘slope’ is about 0.3, for a gentle slope, to 1
33 | /// (the maximum), for a steep slope; the default value is 0.5.
34 | ///
35 | public Width? Width { get; set; }
36 |
37 |
38 | ///
39 | /// Initializes a new instance of the class.
40 | ///
41 | /// Gain value.
42 | public TrebleEffect(double gain)
43 | {
44 | Gain = gain;
45 | }
46 |
47 |
48 | ///
49 | /// Initializes a new instance of the class.
50 | ///
51 | /// Gain value.
52 | /// Central frequency.
53 | public TrebleEffect(double gain, double frequency)
54 | : this(gain)
55 | {
56 | Frequency = frequency;
57 | }
58 |
59 |
60 | ///
61 | /// Initializes a new instance of the class.
62 | ///
63 | /// Gain value.
64 | /// Central frequency.
65 | /// Shelf transition steep.
66 | public TrebleEffect(double gain, double frequency, double width)
67 | : this(gain, frequency)
68 | {
69 | Width = width;
70 | }
71 |
72 |
73 | ///
74 | /// Initializes a new instance of the class.
75 | ///
76 | /// Gain value.
77 | /// Central frequency.
78 | public TrebleEffect(double gain, Frequency frequency)
79 | : this(gain)
80 | {
81 | Frequency = frequency;
82 | }
83 |
84 |
85 | ///
86 | /// Initializes a new instance of the class.
87 | ///
88 | /// Gain value.
89 | /// Central frequency.
90 | /// Shelf transition steep.
91 | public TrebleEffect(double gain, Frequency frequency, Width width)
92 | : this(gain, frequency)
93 | {
94 | Width = width;
95 | }
96 |
97 |
98 | ///
99 | /// Translate a instance to a set of command arguments to be passed to SoX.
100 | /// (invalidates ).
101 | ///
102 | /// A containing SoX command arguments to apply a Treble effect.
103 | public override string ToString()
104 | {
105 | List effectArgs = new List(4) { Name };
106 |
107 | effectArgs.Add(Gain.ToString(CultureInfo.InvariantCulture));
108 |
109 | if (Frequency.HasValue)
110 | effectArgs.Add(Frequency.Value.ToString());
111 |
112 | if (Width.HasValue)
113 | effectArgs.Add(Width.Value.ToString());
114 |
115 | return string.Join(" ", effectArgs);
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/src/Effects/TremoloEffect.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Globalization;
3 |
4 | namespace SoxSharp.Effects
5 | {
6 | ///
7 | /// Apply a tremolo (low frequency amplitude modulation) effect to the audio.
8 | ///
9 | public class TremoloEffect : BaseEffect
10 | {
11 | ///
12 | /// SoX effect name.
13 | ///
14 | public override string Name { get { return "tremolo"; } }
15 |
16 | ///
17 | /// Tremolo frequency in Hz.
18 | ///
19 | public double Speed { get; set; }
20 |
21 | ///
22 | /// Tremolo depth as a percentage (default is 40).
23 | ///
24 | public ushort? Depth { get; set; }
25 |
26 |
27 | public TremoloEffect(double speed)
28 | {
29 | Speed = speed;
30 | }
31 |
32 |
33 | public TremoloEffect(double speed, ushort depth)
34 | : this(speed)
35 | {
36 | Depth = depth;
37 | }
38 |
39 |
40 | ///
41 | /// Translate a instance to a set of command arguments to be passed to SoX.
42 | /// (invalidates ).
43 | ///
44 | /// A containing SoX command arguments to apply a Tremolo effect.
45 | public override string ToString()
46 | {
47 | List effectArgs = new List(3) { Name };
48 |
49 | effectArgs.Add(Speed.ToString(CultureInfo.InvariantCulture));
50 |
51 | if (Depth.HasValue)
52 | effectArgs.Add(Depth.Value.ToString());
53 |
54 | return string.Join(" ", effectArgs);
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Effects/TrimEffect.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using SoxSharp.Effects.Types;
3 |
4 |
5 | namespace SoxSharp.Effects
6 | {
7 | ///
8 | /// Cuts portions out of the audio. Any number of positions may be given; audio is not sent to the output until the
9 | /// first position is reached. The effect then alternates between copying and discarding audio at each position.
10 | /// Using a value of 0 for the first position parameter allows copying from the beginning of the audio.
11 | ///
12 | public class TrimEffect : BaseEffect
13 | {
14 | ///
15 | /// SoX effect name.
16 | ///
17 | public override string Name { get { return "trim"; } }
18 |
19 | ///
20 | /// The positions.
21 | ///
22 | public readonly List Positions = new List();
23 |
24 |
25 | ///
26 | /// Initializes a new instance of the class.
27 | ///
28 | /// Position to use.
29 | public TrimEffect(Position position)
30 | {
31 | Positions.Add(position);
32 | }
33 |
34 |
35 | ///
36 | /// Initializes a new instance of the class.
37 | ///
38 | /// First position to use.
39 | /// Second position to use.
40 | public TrimEffect(Position position1, Position position2)
41 | {
42 | Positions.Add(position1);
43 | Positions.Add(position2);
44 | }
45 |
46 |
47 | ///
48 | /// Initializes a new instance of the class.
49 | ///
50 | /// Positions to use.
51 | public TrimEffect(Position[] positions)
52 | {
53 | Positions.AddRange(positions);
54 | }
55 |
56 |
57 | ///
58 | /// Translate a instance to a set of command arguments to be passed to SoX.
59 | /// (invalidates ).
60 | ///
61 | /// A containing SoX command arguments to apply a Trim effect.
62 | public override string ToString()
63 | {
64 | return Name + " " + string.Join(" ", Positions);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/Effects/Types/FilterType.cs:
--------------------------------------------------------------------------------
1 | namespace SoxSharp.Effects.Types
2 | {
3 | public enum FilterType
4 | {
5 | SinglePole,
6 | DoublePole
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/Effects/Types/Frequency.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 |
3 | namespace SoxSharp.Effects.Types
4 | {
5 | public struct Frequency
6 | {
7 | private readonly double value_;
8 |
9 | private readonly FrequencyUnits? units_;
10 |
11 |
12 | public Frequency(double value)
13 | {
14 | value_ = value;
15 | units_ = null;
16 | }
17 |
18 |
19 | public Frequency(double value, FrequencyUnits units)
20 | {
21 | value_ = value;
22 | units_ = units;
23 | }
24 |
25 |
26 | public static implicit operator Frequency(double value)
27 | {
28 | return new Frequency(value);
29 | }
30 |
31 |
32 | public override string ToString()
33 | {
34 | if (units_.HasValue)
35 | {
36 | switch (units_.Value)
37 | {
38 | case FrequencyUnits.Hz:
39 | return value_.ToString(CultureInfo.InvariantCulture) + "h";
40 |
41 | case FrequencyUnits.KHz:
42 | return value_.ToString(CultureInfo.InvariantCulture) + "k";
43 |
44 | default:
45 | break; // Do nothing.
46 | }
47 | }
48 |
49 | return value_.ToString(CultureInfo.InvariantCulture);
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Effects/Types/FrequencyUnits.cs:
--------------------------------------------------------------------------------
1 | namespace SoxSharp.Effects.Types
2 | {
3 | public enum FrequencyUnits
4 | {
5 | Hz,
6 | KHz
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/Effects/Types/GainType.cs:
--------------------------------------------------------------------------------
1 | namespace SoxSharp.Effects.Types
2 | {
3 | ///
4 | /// When type is amplitude or power, a gain of 1 leaves the volume unchanged, less than 1 decreases it, and greater than 1 increases it; a negative gain inverts the audio signal in addition to adjusting its volume.
5 | ///
6 | public enum GainType
7 | {
8 | ///
9 | /// Gain is an amplitude (i.e. voltage or linear) ratio. A gain of 1 leaves the volume unchanged, less than 1
10 | /// decreases it, and greater than 1 increases it; a negative gain inverts the audio signal in addition to
11 | /// adjusting its volume.
12 | ///
13 | Amplitude,
14 |
15 | ///
16 | /// Gain is a power (i.e. wattage or voltage-squared) ratio. A gain of 1 leaves the volume unchanged, less than 1
17 | /// decreases it, and greater than 1 increases it; a negative gain inverts the audio signal in addition to
18 | /// adjusting its volume.
19 | ///
20 | Power,
21 |
22 | ///
23 | /// Gain is a power change in dB. A gain of 0 leaves the volume unchanged, less than 0 decreases it,
24 | /// and greater than 0 increases it.
25 | ///
26 | Db
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Effects/Types/OptimizationType.cs:
--------------------------------------------------------------------------------
1 | namespace SoxSharp.Effects.Types
2 | {
3 | public enum OptimizationType
4 | {
5 | ///
6 | /// Optimize default values of segment, search and overlap for music processing.
7 | ///
8 | Music,
9 |
10 | ///
11 | /// Optimize default values of segment, search and overlap for speech processing.
12 | ///
13 | Speech,
14 |
15 | ///
16 | /// Optimize default values of segment, search and overlap for ‘linear’ processing that tends to cause more noticeable distortion but may be useful when factor is close to 1.
17 | ///
18 | LinearProcessing
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Effects/Types/Position.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 |
5 | namespace SoxSharp.Effects.Types
6 | {
7 | ///
8 | /// A position within the audio stream.
9 | ///
10 | public struct Position
11 | {
12 | ///
13 | /// Whether the position is to be interpreted relative to the start, end or the previous position if the effect accepts multiple position arguments. The audio length must be known for end-relative locations to work.
14 | ///
15 | private readonly PositionFrom? from_;
16 |
17 | ///
18 | /// Position expressed as a time value.
19 | ///
20 | private readonly TimeSpan? time_;
21 |
22 | ///
23 | /// Position expressed as number of samples.
24 | ///
25 | private readonly uint? samples_;
26 |
27 |
28 | ///
29 | /// Initializes a new instance of the struct.
30 | ///
31 | /// Position expressed as a time value.
32 | public Position(TimeSpan time)
33 | {
34 | time_ = time;
35 | samples_ = null;
36 | from_ = null;
37 | }
38 |
39 |
40 | ///
41 | /// Initializes a new instance of the struct.
42 | ///
43 | /// Position expressed as a time value.
44 | /// How
45 | public Position(TimeSpan time, PositionFrom from)
46 | {
47 | time_ = time;
48 | samples_ = null;
49 | from_ = from;
50 | }
51 |
52 |
53 | ///
54 | /// Initializes a new instance of the struct.
55 | ///
56 | /// Position expressed as number of samples.
57 | public Position(uint samples)
58 | {
59 | time_ = null;
60 | samples_ = samples;
61 | from_ = null;
62 | }
63 |
64 | ///
65 | /// Initializes a new instance of the struct.
66 | ///
67 | /// Position expressed as number of samples.
68 | /// Whether the position is to be interpreted relative to the start, end or the previous position.
69 | public Position(uint samples, PositionFrom from)
70 | {
71 | time_ = null;
72 | samples_ = samples;
73 | from_ = from;
74 | }
75 |
76 |
77 | public static implicit operator Position(uint samples)
78 | {
79 | return new Position(samples);
80 | }
81 |
82 |
83 | public static implicit operator Position(TimeSpan time)
84 | {
85 | return new Position(time);
86 | }
87 |
88 |
89 | public override string ToString()
90 | {
91 | List position = new List(3);
92 |
93 | if (from_.HasValue)
94 | {
95 | switch (from_.Value)
96 | {
97 | case PositionFrom.Start:
98 | position.Add("=");
99 | break;
100 |
101 | case PositionFrom.End:
102 | position.Add("-");
103 | break;
104 |
105 | case PositionFrom.Last:
106 | position.Add("+");
107 | break;
108 |
109 | default:
110 | // Do nothing;
111 | break;
112 | }
113 | }
114 |
115 | if (time_.HasValue)
116 | position.Add(time_.Value.ToString(@"hh\:mm\:ss\.ff"));
117 | else if (samples_.HasValue)
118 | position.Add(samples_.Value.ToString() + "s");
119 |
120 | return string.Join("", position);
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/Effects/Types/PositionFrom.cs:
--------------------------------------------------------------------------------
1 | namespace SoxSharp.Effects.Types
2 | {
3 | public enum PositionFrom
4 | {
5 | Start,
6 | End,
7 | Last
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/Effects/Types/Width.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 | using System.Globalization;
4 |
5 | namespace SoxSharp.Effects.Types
6 | {
7 | public struct Width
8 | {
9 | private readonly double value_;
10 |
11 | private readonly WidthUnits? units_;
12 |
13 |
14 | public Width(double value)
15 | {
16 | value_ = value;
17 | units_ = null;
18 | }
19 |
20 |
21 | public Width(double value, WidthUnits units)
22 | {
23 | value_ = value;
24 | units_ = units;
25 | }
26 |
27 |
28 | public static implicit operator Width(double value)
29 | {
30 | return new Width(value);
31 | }
32 |
33 |
34 | public override string ToString()
35 | {
36 | if (units_.HasValue)
37 | {
38 | switch (units_.Value)
39 | {
40 | case WidthUnits.Hz:
41 | return value_.ToString(CultureInfo.InvariantCulture) + "h";
42 |
43 | case WidthUnits.KHz:
44 | return value_.ToString(CultureInfo.InvariantCulture) + "k";
45 |
46 | case WidthUnits.Octaves:
47 | return value_.ToString(CultureInfo.InvariantCulture) + "o";
48 |
49 | case WidthUnits.Qfactor:
50 | return value_.ToString(CultureInfo.InvariantCulture) + "q";
51 |
52 | default:
53 | break; // Do nothing.
54 | }
55 | }
56 |
57 | return value_.ToString(CultureInfo.InvariantCulture);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Effects/Types/WidthUnits.cs:
--------------------------------------------------------------------------------
1 | namespace SoxSharp.Effects.Types
2 | {
3 | public enum WidthUnits
4 | {
5 | Hz,
6 | KHz,
7 | Octaves,
8 | Qfactor
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/Effects/VolumeEffect.cs:
--------------------------------------------------------------------------------
1 | using SoxSharp.Effects.Types;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 |
5 | namespace SoxSharp.Effects
6 | {
7 | ///
8 | /// Apply an amplification or an attenuation to the audio signal.
9 | ///
10 | public class VolumeEffect : BaseEffect
11 | {
12 | ///
13 | /// SoX effect name.
14 | ///
15 | public override string Name { get { return "vol"; } }
16 |
17 | ///
18 | /// The amount to change the volume, interpreted according to the given type.
19 | ///
20 | public double Gain { get; set; }
21 |
22 | ///
23 | /// How to interpret the gain value.
24 | ///
25 | public GainType? Type { get; set; }
26 |
27 | ///
28 | /// Used only on peaks to prevent clipping. Should be a value much less than 1 (e.g. 0.05 or 0.02).
29 | ///
30 | public double? Limiter { get; set; }
31 |
32 |
33 | ///
34 | /// Initializes a new instance of the class.
35 | ///
36 | /// Volume gain.
37 | public VolumeEffect(double gain)
38 | {
39 | Gain = gain;
40 | }
41 |
42 |
43 | ///
44 | /// Initializes a new instance of the class.
45 | ///
46 | /// Volume gain.
47 | /// How to interpret the gain value.
48 | public VolumeEffect(double gain, GainType type)
49 | : this(gain)
50 | {
51 | Type = type;
52 | }
53 |
54 |
55 | ///
56 | /// Initializes a new instance of the class.
57 | ///
58 | /// Volume gain.
59 | /// How to interpret the gain value.
60 | /// Gain limiter.
61 | public VolumeEffect(double gain, GainType type, double limiter)
62 | : this(gain, type)
63 | {
64 | Limiter = limiter;
65 | }
66 |
67 |
68 | ///
69 | /// Translate a instance to a set of command arguments to be passed to SoX to be applied
70 | /// to the input file (invalidates ).
71 | ///
72 | /// A containing SoX command arguments to apply a Volume effect.
73 | public override string ToString()
74 | {
75 | List effectArgs = new List(4) { Name };
76 | effectArgs.Add(Gain.ToString(CultureInfo.InvariantCulture));
77 |
78 | if (Type.HasValue)
79 | {
80 | switch (Type.Value)
81 | {
82 | case GainType.Amplitude:
83 |
84 | effectArgs.Add("amplitude");
85 | break;
86 |
87 | case GainType.Power:
88 |
89 | effectArgs.Add("power");
90 | break;
91 |
92 | case GainType.Db:
93 |
94 | effectArgs.Add("dB");
95 | break;
96 |
97 | default:
98 | // Do nothing.
99 | break;
100 | }
101 | }
102 |
103 | if (Limiter.HasValue)
104 | effectArgs.Add(Limiter.Value.ToString(CultureInfo.InvariantCulture));
105 |
106 | return string.Join(" ", effectArgs);
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/Events.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 |
4 | namespace SoxSharp
5 | {
6 | ///
7 | /// Provides data for the event.
8 | ///
9 | public class LogMessageEventArgs : EventArgs
10 | {
11 | ///
12 | /// Initializes a instance with the provided values.
13 | ///
14 | /// Message severity.
15 | /// Message source.
16 | /// Message text.
17 | public LogMessageEventArgs(LogLevelType logLevel, string source, string message)
18 | {
19 | LogLevel = logLevel;
20 | Source = source;
21 | Message = message;
22 | }
23 |
24 | ///
25 | /// Message severity.
26 | ///
27 | public LogLevelType LogLevel { get; private set; }
28 |
29 | ///
30 | /// SoX logger module.
31 | ///
32 | public string Source { get; private set; }
33 |
34 | ///
35 | /// Message text.
36 | ///
37 | public string Message { get; private set; }
38 | }
39 |
40 |
41 | ///
42 | /// Provides data for the event.
43 | ///
44 | public class ProgressEventArgs : EventArgs
45 | {
46 | ///
47 | /// Initializes a instance with the provided values.
48 | ///
49 | /// The actual progress value, from 0 to 100.
50 | /// File time that has been processed, based on file total duration.
51 | /// File time pending to be processed, based on file total duration.
52 | /// Actual size of the generated output file.
53 | public ProgressEventArgs(UInt16 progress, TimeSpan processed, TimeSpan remaining, UInt64 outputSize)
54 | {
55 | if (progress > 100)
56 | Progress = 100;
57 | else
58 | Progress = progress;
59 |
60 | Processed = processed;
61 | Remaining = remaining;
62 | OutputSize = outputSize;
63 | Abort = false;
64 | }
65 |
66 | ///
67 | /// The actual progress value, from 0 to 100.
68 | ///
69 | public UInt16 Progress { get; private set; }
70 |
71 | ///
72 | /// File time that has been processed, based on file total duration.
73 | ///
74 | public TimeSpan Processed { get; private set; }
75 |
76 | ///
77 | /// File time pending to be processed, based on file total duration.
78 | ///
79 | public TimeSpan Remaining { get; private set; }
80 |
81 | ///
82 | /// Actual size of the generated output file.
83 | ///
84 | public UInt64 OutputSize { get; private set; }
85 |
86 | ///
87 | /// Allows to cancel the current operation.
88 | ///
89 | /// true to cancel; otherwise, leave as false.
90 | public bool Abort { get; set; }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/Exceptions/SoxEffectException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 |
4 | namespace SoxSharp.Exceptions
5 | {
6 | ///
7 | /// Exception that is thrown when trying to apply an Effect which caontains invalid data.
8 | ///
9 | public class SoxEffectException : SoxException
10 | {
11 | ///
12 | /// Name of the effect that caused the exception.
13 | ///
14 | public string EffectName { get; private set; }
15 |
16 | ///
17 | /// Initializes a new instance of the class with its message string set
18 | /// to a default message.
19 | ///
20 | /// The effect name.
21 | public SoxEffectException(string effectName)
22 | {
23 | EffectName = effectName;
24 | }
25 |
26 | ///
27 | /// Initializes a new instance of the class with a specified message.
28 | ///
29 | /// The effect name.
30 | /// The exception's message.
31 | public SoxEffectException(string effectName, string message)
32 | : base(message)
33 | {
34 | EffectName = effectName;
35 | }
36 |
37 | ///
38 | /// Initializes a new instance of the class with a specified message and a
39 | /// reference to the inner exception that is the cause of this exception.
40 | ///
41 | /// The effect name.
42 | /// The exception's message.
43 | /// Exception that caused it.
44 | public SoxEffectException(string effectName, string message, Exception inner)
45 | : base(message, inner)
46 | {
47 | EffectName = effectName;
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Exceptions/SoxException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 |
4 | namespace SoxSharp.Exceptions
5 | {
6 | ///
7 | /// Generic SoX exception.
8 | ///
9 | public class SoxException : Exception
10 | {
11 | ///
12 | /// Initializes a new instance of the class with its message string set
13 | /// to a default message.
14 | ///
15 | public SoxException()
16 | {
17 | }
18 |
19 | ///
20 | /// Initializes a new instance of the class with a specified message.
21 | ///
22 | /// The exception's message.
23 | public SoxException(string message)
24 | : base(message)
25 | {
26 | }
27 |
28 | ///
29 | /// Initializes a new instance of the class with a specified message and a
30 | /// reference to the inner exception that is the cause of this exception.
31 | ///
32 | /// The exception's message.
33 | /// Exception that caused it.
34 | public SoxException(string message, Exception inner)
35 | : base(message, inner)
36 | {
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Exceptions/SoxUnexpectedOutputException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 |
4 | namespace SoxSharp.Exceptions
5 | {
6 | ///
7 | /// Exception that is thrown when SoX output doesn't match the expected regular expression.
8 | ///
9 | public class SoxUnexpectedOutputException: SoxException
10 | {
11 | ///
12 | /// Initializes a new instance of the class with an output string.
13 | ///
14 | /// SoX unexpected output string.
15 | public SoxUnexpectedOutputException(string output)
16 | : base(output)
17 | {
18 | }
19 |
20 |
21 | ///
22 | /// Initializes a new instance of the class with an output string
23 | /// and a reference to the inner exception that is the cause of this exception.
24 | ///
25 | /// SoX unexpected output string.
26 | /// Exception that caused it.
27 | public SoxUnexpectedOutputException(string output, Exception inner)
28 | : base(output, inner)
29 | {
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/FormatOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 |
5 | namespace SoxSharp
6 | {
7 | ///
8 | /// Format options that are applicable to both input and output files.
9 | ///
10 | public abstract class FormatOptions
11 | {
12 | ///
13 | /// Audio file type.
14 | ///
15 | public FileType? Type { get; set; }
16 |
17 | ///
18 | /// Audio encoding.
19 | ///
20 | public EncodingType? Encoding { get; set; }
21 |
22 | ///
23 | /// Sample size (bits).
24 | ///
25 | public ushort? SampleSize { get; set; }
26 |
27 | ///
28 | /// Encoded nibble order.
29 | ///
30 | public bool? ReverseNibbles { get; set; }
31 |
32 | ///
33 | /// Encoded bit order.
34 | ///
35 | public bool? ReverseBits { get; set; }
36 |
37 | ///
38 | /// Encoded byte order.
39 | ///
40 | public ByteOrderType? ByteOrder { get; set; }
41 |
42 | ///
43 | /// Number of audio channels.
44 | ///
45 | public ushort? Channels { get; set; }
46 |
47 | ///
48 | /// Audio sample rate.
49 | ///
50 | public uint? SampleRate { get; set; }
51 |
52 | ///
53 | /// Allow glob wildcard match filename.
54 | ///
55 | public bool? Glob { get; set; }
56 |
57 | ///
58 | /// Custom format arguments.
59 | ///
60 | public string CustomArgs { get; set; }
61 |
62 | ///
63 | /// Default constructor.
64 | ///
65 | protected FormatOptions()
66 | {
67 | }
68 |
69 |
70 | ///
71 | /// Translate a instance to a set of command arguments to be passed to SoX (invalidates ).
72 | ///
73 | /// String containing SoX command arguments.
74 | public override string ToString()
75 | {
76 | var formatOptions = new List();
77 |
78 | if (Type.HasValue)
79 | formatOptions.Add("--type " + Type.Value.ToString().ToLower());
80 |
81 | if (Encoding.HasValue)
82 | {
83 | switch (Encoding.Value)
84 | {
85 | case EncodingType.ALaw: formatOptions.Add("--encoding a-law"); break;
86 | case EncodingType.FloatingPoint: formatOptions.Add("--encoding floating-point"); break;
87 | case EncodingType.GsmFullRate: formatOptions.Add("--encoding gsm-full-rate"); break;
88 | case EncodingType.ImaAdpcm: formatOptions.Add("--encoding ima-adpcm"); break;
89 | case EncodingType.MsAdpcm: formatOptions.Add("--encoding ms-pcm"); break;
90 | case EncodingType.MuLaw: formatOptions.Add("--encoding mu-law"); break;
91 | case EncodingType.SignedInteger: formatOptions.Add("--encoding signed-integer"); break;
92 | case EncodingType.UnsignedInteger: formatOptions.Add("--encoding unsigned-integer"); break;
93 | default: break; // Do nothing.
94 | }
95 | }
96 |
97 | if (SampleSize.HasValue)
98 | formatOptions.Add("--bits " + SampleSize.Value);
99 |
100 | if (ReverseNibbles.HasValue && (ReverseNibbles.Value == true))
101 | formatOptions.Add("--reverse-nibbles");
102 |
103 | if (ReverseBits.HasValue && (ReverseBits.Value == true))
104 | formatOptions.Add("--reverse-bits");
105 |
106 | if (ByteOrder.HasValue)
107 | {
108 | switch (ByteOrder.Value)
109 | {
110 | case ByteOrderType.BigEndian: formatOptions.Add("--endian big"); break;
111 | case ByteOrderType.LittleEndian: formatOptions.Add("--endian little"); break;
112 | case ByteOrderType.Swap: formatOptions.Add("--endian swap"); break;
113 | default: break; // Do nothing.
114 | }
115 | }
116 |
117 | if (Channels.HasValue)
118 | formatOptions.Add("--channels " + Channels.Value);
119 |
120 | if (SampleRate.HasValue)
121 | formatOptions.Add("--rate " + SampleRate.Value);
122 |
123 | if (Glob.HasValue && (Glob.Value == false))
124 | formatOptions.Add("--no-glob");
125 |
126 | if (!string.IsNullOrEmpty(CustomArgs))
127 | formatOptions.Add(CustomArgs);
128 |
129 | return string.Join(" ", formatOptions);
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/src/FormattedSize.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 |
4 |
5 | namespace SoxSharp
6 | {
7 | ///
8 | /// Utility class that converts a a SoX file size string (an integer or double value, optionally followed by a k, M or G character) to a numeric value.
9 | ///
10 | public static class FormattedSize
11 | {
12 | ///
13 | /// Converts a SoX file size string to a value.
14 | ///
15 | /// Size string.
16 | /// Numeric value.
17 | public static UInt64 ToUInt64(string formattedSize)
18 | {
19 | UInt64 multiplier = 1;
20 |
21 | if (formattedSize.EndsWith("k", StringComparison.InvariantCulture))
22 | {
23 | multiplier = 1024;
24 | formattedSize = formattedSize.Substring(0, formattedSize.Length - 1);
25 | }
26 |
27 | else if (formattedSize.EndsWith("M", StringComparison.InvariantCulture))
28 | {
29 | multiplier = 1024 * 1024;
30 | formattedSize = formattedSize.Substring(0, formattedSize.Length - 1);
31 | }
32 |
33 | else if (formattedSize.EndsWith("G", StringComparison.InvariantCulture))
34 | {
35 | multiplier = 1024 * 1024 * 1024;
36 | formattedSize = formattedSize.Substring(0, formattedSize.Length - 1);
37 | }
38 |
39 | return Convert.ToUInt64(double.Parse(formattedSize, CultureInfo.InvariantCulture)) * multiplier;
40 | }
41 |
42 |
43 | ///
44 | /// Converts a SoX file size string to a value.
45 | ///
46 | /// Size string.
47 | /// Numeric value.
48 | public static UInt32 ToUInt32(string formattedSize)
49 | {
50 | UInt32 multiplier = 1;
51 |
52 | if (formattedSize.EndsWith("k", StringComparison.InvariantCulture))
53 | {
54 | multiplier = 1024;
55 | formattedSize = formattedSize.Substring(0, formattedSize.Length - 1);
56 | }
57 |
58 | else if (formattedSize.EndsWith("M", StringComparison.InvariantCulture))
59 | {
60 | multiplier = 1024 * 1024;
61 | formattedSize = formattedSize.Substring(0, formattedSize.Length - 1);
62 | }
63 |
64 | else if (formattedSize.EndsWith("G", StringComparison.InvariantCulture))
65 | {
66 | multiplier = 1024 * 1024 * 1024;
67 | formattedSize = formattedSize.Substring(0, formattedSize.Length - 1);
68 | }
69 |
70 | return Convert.ToUInt32(double.Parse(formattedSize, CultureInfo.InvariantCulture)) * multiplier;
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/InputFile.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 |
5 | namespace SoxSharp
6 | {
7 | ///
8 | /// Input format options.
9 | ///
10 | public class InputFile : FormatOptions
11 | {
12 | ///
13 | /// Input file name.
14 | ///
15 | public string FileName { get; set; }
16 |
17 | ///
18 | /// Input file volume adjustment factor.
19 | ///
20 | public double? Volume { get; set; }
21 |
22 | ///
23 | /// Ignore input file length given in header and read to EOF.
24 | ///
25 | public bool? IgnoreLength { get; set; }
26 |
27 |
28 | ///
29 | /// Initializes a new instance of the class.
30 | ///
31 | public InputFile()
32 | : base()
33 | {
34 | }
35 |
36 |
37 | ///
38 | /// Initializes a new instance of the class.
39 | ///
40 | public InputFile(string fileName)
41 | : base()
42 | {
43 | FileName = fileName;
44 | }
45 |
46 |
47 | ///
48 | /// Translate a instance to a set of command arguments to be passed to SoX to be applied to the input file (invalidates ).
49 | ///
50 | /// String containing SoX command arguments.
51 | public override string ToString()
52 | {
53 | List inputOptions = new List(4);
54 |
55 | string baseStr = base.ToString();
56 |
57 | if (!string.IsNullOrEmpty(baseStr))
58 | inputOptions.Add(baseStr);
59 |
60 | if (Volume.HasValue)
61 | inputOptions.Add("--volume " + Volume.Value);
62 |
63 | if (IgnoreLength.HasValue && (IgnoreLength.Value == true))
64 | inputOptions.Add("--ignore-length");
65 |
66 | if (!string.IsNullOrEmpty(FileName))
67 | {
68 | if (FileName.Contains(" "))
69 | {
70 | if ((Environment.OSVersion.Platform == PlatformID.Win32NT) ||
71 | (Environment.OSVersion.Platform == PlatformID.Win32Windows) ||
72 | (Environment.OSVersion.Platform == PlatformID.Win32S) ||
73 | (Environment.OSVersion.Platform == PlatformID.WinCE))
74 | inputOptions.Add("\"" + FileName + "\"");
75 | else
76 | inputOptions.Add("'" + FileName + "'");
77 | }
78 | else
79 | inputOptions.Add(FileName);
80 | }
81 | else
82 | inputOptions.Add("--null");
83 |
84 | return string.Join(" ", inputOptions);
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/OutputFormatOptions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 |
4 | namespace SoxSharp
5 | {
6 | ///
7 | /// Format options to be applied to the output file. For any property not set here, SoX will infer the value from the input file.
8 | ///
9 | public class OutputFormatOptions : FormatOptions
10 | {
11 | ///
12 | /// Compression factor for output format.
13 | ///
14 | public double? Compression { get; set; }
15 |
16 | ///
17 | /// Set comment for output file.
18 | ///
19 | public string Comment { get; set; }
20 |
21 | ///
22 | /// Add comment to output file.
23 | ///
24 | public string AddComment { get; set; }
25 |
26 |
27 | ///
28 | /// Initializes a new instance of the class.
29 | ///
30 | public OutputFormatOptions()
31 | : base()
32 | {
33 | }
34 |
35 |
36 | ///
37 | /// Translate a instance to a set of command arguments to be passed to SoX (adds additional command arguments to ).
38 | ///
39 | /// String containing SoX command arguments.
40 | public override string ToString()
41 | {
42 | List outputOptions = new List(4);
43 |
44 | string baseStr = base.ToString();
45 |
46 | if (!string.IsNullOrEmpty(baseStr))
47 | outputOptions.Add(baseStr);
48 |
49 | if (Compression.HasValue)
50 | outputOptions.Add("--compression " + Compression.Value);
51 |
52 | if (AddComment != null)
53 | outputOptions.Add("--add-comment \"" + AddComment + "\"");
54 |
55 | if (Comment != null)
56 | outputOptions.Add("--comment \"" + Comment + "\"");
57 |
58 | return string.Join(" ", outputOptions);
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // Este código fue generado por una herramienta.
4 | // Versión de runtime:4.0.30319.42000
5 | //
6 | // Los cambios en este archivo podrían causar un comportamiento incorrecto y se perderán si
7 | // se vuelve a generar el código.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace SoxSharp {
12 | using System;
13 |
14 |
15 | ///
16 | /// Clase de recurso fuertemente tipado, para buscar cadenas traducidas, etc.
17 | ///
18 | // StronglyTypedResourceBuilder generó automáticamente esta clase
19 | // a través de una herramienta como ResGen o Visual Studio.
20 | // Para agregar o quitar un miembro, edite el archivo .ResX y, a continuación, vuelva a ejecutar ResGen
21 | // con la opción /str o recompile su proyecto de VS.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Devuelve la instancia de ResourceManager almacenada en caché utilizada por esta clase.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SoxSharp.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Reemplaza la propiedad CurrentUICulture del subproceso actual para todas las
51 | /// búsquedas de recursos mediante esta clase de recurso fuertemente tipado.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 |
--------------------------------------------------------------------------------
/src/Sox.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Globalization;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Text.RegularExpressions;
8 | using SoxSharp.Effects;
9 | using SoxSharp.Exceptions;
10 |
11 |
12 | namespace SoxSharp
13 | {
14 | ///
15 | /// Encapsulates all the information needed to launch SoX and handle its output.
16 | ///
17 | public class Sox : IDisposable
18 | {
19 | ///
20 | /// Provides updated progress status while SoX is being executed.
21 | ///
22 | public event EventHandler OnProgress = null;
23 |
24 | ///
25 | /// Occurs when SoX generates any non-FAIL log message.
26 | ///
27 | public event EventHandler OnLogMessage = null;
28 |
29 | ///
30 | /// Location of the SoX executable to be used by the library.
31 | ///
32 | /// The executable path.
33 | public string Path { get; set; }
34 |
35 | ///
36 | /// Size of all processing buffers (default is 8192).
37 | ///
38 | public uint? Buffer { get; set; }
39 |
40 | ///
41 | /// Enable parallel effects channels processing (where available).
42 | ///
43 | public bool? Multithreaded { get; set; }
44 |
45 | ///
46 | /// Output format options.
47 | ///
48 | public OutputFormatOptions Output { get; private set; }
49 |
50 | ///
51 | /// Effects to be applied.
52 | ///
53 | public List Effects { get; private set; }
54 |
55 | ///
56 | /// Custom global arguments.
57 | ///
58 | public string CustomArgs { get; set; }
59 |
60 | ///
61 | /// Custom effects. Add here the command line arguments for any effect not currently implemented in SoXSharp.
62 | ///
63 | public string CustomEffects { get; set; }
64 |
65 | ///
66 | /// Gets the full command line of the last call to SoX.
67 | ///
68 | public string LastCommand { get; private set; }
69 |
70 |
71 | private SoxProcess soxProcess_ = null;
72 | private string lastError_ = null;
73 | private string lastErrorSource_ = null;
74 | private bool disposed_ = false;
75 |
76 |
77 | ///
78 | /// Initializes a new instance of the class.
79 | ///
80 | /// Location of the SoX executable to be used by the library.
81 | public Sox(string path)
82 | {
83 | Output = new OutputFormatOptions();
84 | Effects = new List();
85 | Path = path;
86 | }
87 |
88 |
89 | ~Sox()
90 | {
91 | Dispose(false);
92 | }
93 |
94 |
95 | ///
96 | /// Releases all resource used by the object.
97 | ///
98 | /// Call when you are finished using the instance. This
99 | /// method leaves the instance in an unusable state. After calling
100 | /// it, you must release all references to the instance so the garbage
101 | /// collector can reclaim the memory that it was occupying.
102 | public void Dispose()
103 | {
104 | Dispose(true);
105 | GC.SuppressFinalize(this);
106 | }
107 |
108 |
109 | ///
110 | /// Gets information about the given file.
111 | ///
112 | /// File information as a instance.
113 | /// Input file.
114 | public AudioInfo GetInfo(string inputFile)
115 | {
116 | if (!File.Exists(inputFile))
117 | throw new FileNotFoundException("File not found: " + inputFile);
118 |
119 | soxProcess_ = SoxProcess.Create(Path);
120 |
121 | lastError_ = null;
122 | lastErrorSource_ = null;
123 |
124 | try
125 | {
126 | soxProcess_.StartInfo.RedirectStandardOutput = true;
127 |
128 | if (inputFile.Contains(" "))
129 | {
130 | if ((Environment.OSVersion.Platform == PlatformID.Win32NT) ||
131 | (Environment.OSVersion.Platform == PlatformID.Win32Windows) ||
132 | (Environment.OSVersion.Platform == PlatformID.Win32S) ||
133 | (Environment.OSVersion.Platform == PlatformID.WinCE))
134 | soxProcess_.StartInfo.Arguments = "--info \"" + inputFile + "\"";
135 | else
136 | soxProcess_.StartInfo.Arguments = "--info '" + inputFile + "'";
137 | }
138 | else
139 | soxProcess_.StartInfo.Arguments = "--info " + inputFile;
140 |
141 | soxProcess_.Start();
142 |
143 | LastCommand = Path + " " + soxProcess_.StartInfo.Arguments;
144 |
145 | string output = soxProcess_.StandardOutput.ReadToEnd();
146 |
147 | if (String.IsNullOrEmpty(output))
148 | output = soxProcess_.StandardError.ReadToEnd();
149 |
150 | if (soxProcess_.WaitForExit(10000) == false)
151 | throw new TimeoutException("SoX response timeout");
152 |
153 | CheckForLogMessage(output);
154 |
155 | if (output != null)
156 | {
157 | Match matchInfo = SoxProcess.InfoRegex.Match(output);
158 |
159 | if (matchInfo.Success)
160 | {
161 | try
162 | {
163 | UInt16 channels = Convert.ToUInt16(double.Parse(matchInfo.Groups[1].Value, CultureInfo.InvariantCulture));
164 | UInt32 sampleRate = Convert.ToUInt32(double.Parse(matchInfo.Groups[2].Value, CultureInfo.InvariantCulture));
165 | UInt16 sampleSize = Convert.ToUInt16(double.Parse(new string(matchInfo.Groups[3].Value.Where(Char.IsDigit).ToArray()), CultureInfo.InvariantCulture));
166 | TimeSpan duration = Utils.TimeSpanFromString(matchInfo.Groups[4].Value);
167 | UInt64 size = FormattedSize.ToUInt64(matchInfo.Groups[5].Value);
168 | UInt32 bitRate = FormattedSize.ToUInt32(matchInfo.Groups[6].Value);
169 | string encoding = matchInfo.Groups[7].Value;
170 |
171 | return new AudioInfo(channels, sampleRate, sampleSize, duration, size, bitRate, encoding);
172 | }
173 |
174 | catch (Exception ex)
175 | {
176 | throw new SoxUnexpectedOutputException(output, ex);
177 | }
178 | }
179 | }
180 |
181 | throw new SoxUnexpectedOutputException(output != null ? output : "No output received");
182 | }
183 |
184 | finally
185 | {
186 | if (soxProcess_ != null)
187 | {
188 | soxProcess_.Dispose();
189 | soxProcess_ = null;
190 | }
191 | }
192 | }
193 |
194 |
195 | ///
196 | /// Spawns a new SoX process using the specified options in this instance and record audio the specified file.
197 | ///
198 | /// Audio file to be recorded.
199 | public void Record(string outputFile)
200 | {
201 | Process("--default-device", outputFile);
202 | }
203 |
204 |
205 | ///
206 | /// Spawns a new SoX process using the specified options in this instance and plays the specified file.
207 | ///
208 | /// Audio file to be played.
209 | public void Play(string inputFile)
210 | {
211 | Process(new InputFile[] { new InputFile(inputFile) }, "--default-device");
212 | }
213 |
214 |
215 | ///
216 | /// Spawns a new SoX process using the specified options in this instance and plays the specified file.
217 | ///
218 | /// Audio file to be played.
219 | public void Play(InputFile inputFile)
220 | {
221 | Process(new InputFile[] { inputFile }, "--default-device");
222 | }
223 |
224 |
225 | ///
226 | /// Spawns a new SoX process using the specified options in this instance and plays the specified files.
227 | ///
228 | /// Audio files to be played.
229 | public void Play(string[] inputFiles)
230 | {
231 | var inputs = new List(inputFiles.Length);
232 |
233 | foreach (var inputFile in inputFiles)
234 | inputs.Add(new InputFile(inputFile));
235 |
236 | Process(inputs.ToArray(), "--default-device");
237 | }
238 |
239 |
240 | ///
241 | /// Spawns a new SoX process using the specified options in this instance and plays the specified files.
242 | ///
243 | /// Audio files to be played.
244 | /// How to combine the input files.
245 | public void Play(string[] inputFiles, CombinationType combination)
246 | {
247 | var inputs = new List(inputFiles.Length);
248 |
249 | foreach (var inputFile in inputFiles)
250 | inputs.Add(new InputFile(inputFile));
251 |
252 | Process(inputs.ToArray(), "--default-device", combination);
253 | }
254 |
255 |
256 | ///
257 | /// Spawns a new SoX process using the specified options in this instance and plays the specified files.
258 | ///
259 | /// Audio files to be played.
260 | public void Play(InputFile[] inputFiles)
261 | {
262 | Process(inputFiles, "--default-device");
263 | }
264 |
265 |
266 | ///
267 | /// Spawns a new SoX process using the specified options in this instance and plays the specified files.
268 | ///
269 | /// Audio files to be played.
270 | /// How to combine the input files.
271 | public void Play(InputFile[] inputFiles, CombinationType combination)
272 | {
273 | Process(inputFiles, "--default-device", combination);
274 | }
275 |
276 |
277 | ///
278 | /// Spawns a new SoX process using the specified options in this instance.
279 | ///
280 | /// Audio file to be processed.
281 | public void Process(string inputFile)
282 | {
283 | Process(new InputFile[] { new InputFile(inputFile) }, null);
284 | }
285 |
286 |
287 | ///
288 | /// Spawns a new SoX process using the specified options in this instance.
289 | ///
290 | /// Audio file to be processed.
291 | public void Process(InputFile inputFile)
292 | {
293 | Process(new InputFile[] { inputFile }, null);
294 | }
295 |
296 |
297 | ///
298 | /// Spawns a new SoX process using the specified options in this instance.
299 | ///
300 | /// Audio file to be processed.
301 | /// Output file.
302 | public void Process(string inputFile, string outputFile)
303 | {
304 | Process(new InputFile[] { new InputFile(inputFile) }, outputFile);
305 | }
306 |
307 |
308 | ///
309 | /// Spawns a new SoX process using the specified options in this instance.
310 | ///
311 | /// Audio file to be processed.
312 | /// Output file.
313 | public void Process(InputFile inputFile, string outputFile)
314 | {
315 | Process(new InputFile[] { inputFile }, outputFile);
316 | }
317 |
318 |
319 | ///
320 | /// Spawns a new SoX process using the specified options in this instance.
321 | ///
322 | /// First audio file to be processed.
323 | /// Second audio file to be processed.
324 | /// Output file.
325 | public void Process(string inputFile1, string inputFile2, string outputFile)
326 | {
327 | Process(new InputFile[] { new InputFile(inputFile1), new InputFile(inputFile2) }, outputFile);
328 | }
329 |
330 |
331 | ///
332 | /// Spawns a new SoX process using the specified options in this instance.
333 | ///
334 | /// First audio file to be processed.
335 | /// Second audio file to be processed.
336 | /// Output file.
337 | /// How to combine the input files.
338 | public void Process(string inputFile1, string inputFile2, string outputFile, CombinationType combination)
339 | {
340 | Process(new InputFile[] { new InputFile(inputFile1), new InputFile(inputFile2) }, outputFile, combination);
341 | }
342 |
343 |
344 | ///
345 | /// Spawns a new SoX process using the specified options in this instance.
346 | ///
347 | /// First audio file to be processed.
348 | /// Second audio file to be processed.
349 | /// Output file.
350 | public void Process(InputFile inputFile1, InputFile inputFile2, string outputFile)
351 | {
352 | Process(new InputFile[] { inputFile1, inputFile2 }, outputFile);
353 | }
354 |
355 |
356 | ///
357 | /// Spawns a new SoX process using the specified options in this instance.
358 | ///
359 | /// First audio file to be processed.
360 | /// Second audio file to be processed.
361 | /// Output file.
362 | /// How to combine the input files.
363 | public void Process(InputFile inputFile1, InputFile inputFile2, string outputFile, CombinationType combination)
364 | {
365 | Process(new InputFile[] { inputFile1, inputFile2 }, outputFile, combination);
366 | }
367 |
368 |
369 | ///
370 | /// Spawns a new SoX process using the specified options in this instance.
371 | ///
372 | /// Audio files to be processed.
373 | /// Output file.
374 | public void Process(string[] inputFiles, string outputFile)
375 | {
376 | var inputs = new List(inputFiles.Length);
377 |
378 | foreach (var inputFile in inputFiles)
379 | inputs.Add(new InputFile(inputFile));
380 |
381 | Process(inputs.ToArray(), outputFile);
382 | }
383 |
384 |
385 | ///
386 | /// Spawns a new SoX process using the specified options in this instance.
387 | ///
388 | /// Audio files to be processed.
389 | /// Output file.
390 | /// How to combine the input files.
391 | public void Process(string[] inputFiles, string outputFile, CombinationType combination)
392 | {
393 | var inputs = new List(inputFiles.Length);
394 |
395 | foreach (var inputFile in inputFiles)
396 | inputs.Add(new InputFile(inputFile));
397 |
398 | Process(inputs.ToArray(), outputFile, combination);
399 | }
400 |
401 |
402 | ///
403 | /// Spawns a new SoX process using the specified options in this instance.
404 | ///
405 | /// Audio files to be processed.
406 | /// Output file.
407 | public void Process(InputFile[] inputFiles, string outputFile)
408 | {
409 | Process(inputFiles, outputFile, CombinationType.Default);
410 | }
411 |
412 |
413 | ///
414 | /// Spawns a new SoX process using the specified options in this instance.
415 | ///
416 | /// Audio files to be processed.
417 | /// Output file.
418 | /// How to combine the input files.
419 | public void Process(InputFile[] inputFiles, string outputFile, CombinationType combination)
420 | {
421 | soxProcess_ = SoxProcess.Create(Path);
422 |
423 | lastError_ = null;
424 | lastErrorSource_ = null;
425 |
426 | try
427 | {
428 | soxProcess_.ErrorDataReceived += OnSoxProcessOutputReceived;
429 | soxProcess_.OutputDataReceived += OnSoxProcessOutputReceived;
430 |
431 | List args = new List();
432 |
433 | // Global options.
434 |
435 | if (Buffer.HasValue)
436 | args.Add("--buffer " + Buffer.Value);
437 |
438 | if (Multithreaded.HasValue)
439 | args.Add(Multithreaded.Value ? "--multi-threaded" : "--single-threaded");
440 |
441 | if (!String.IsNullOrEmpty(CustomArgs))
442 | args.Add(CustomArgs);
443 |
444 | switch (combination)
445 | {
446 | case CombinationType.Concatenate:
447 | args.Add("--combine concatenate");
448 | break;
449 |
450 | case CombinationType.Merge:
451 | args.Add("--combine merge");
452 | break;
453 |
454 | case CombinationType.Mix:
455 | args.Add("--combine mix");
456 | break;
457 |
458 | case CombinationType.MixPower:
459 | args.Add("--combine mix-power");
460 | break;
461 |
462 | case CombinationType.Multiply:
463 | args.Add("--combine multiply");
464 | break;
465 |
466 | case CombinationType.Sequence:
467 | args.Add("--combine sequence");
468 | break;
469 |
470 | default:
471 | // Do nothing.
472 | break;
473 | }
474 |
475 | args.Add("--show-progress");
476 |
477 | // Input options and files.
478 |
479 | if ((inputFiles != null) && (inputFiles.Length > 0))
480 | {
481 | foreach (InputFile inputFile in inputFiles)
482 | args.Add(inputFile.ToString());
483 | }
484 | else
485 | args.Add("--null");
486 |
487 | // Output options and file.
488 |
489 | args.Add(Output.ToString());
490 |
491 | if (!string.IsNullOrEmpty(outputFile))
492 | {
493 | if (outputFile.Contains(" "))
494 | {
495 | if ((Environment.OSVersion.Platform == PlatformID.Win32NT) ||
496 | (Environment.OSVersion.Platform == PlatformID.Win32Windows) ||
497 | (Environment.OSVersion.Platform == PlatformID.Win32S) ||
498 | (Environment.OSVersion.Platform == PlatformID.WinCE))
499 | args.Add("\"" + outputFile + "\"");
500 | else
501 | args.Add("'" + outputFile + "'");
502 | }
503 | else
504 | args.Add(outputFile);
505 | }
506 | else
507 | args.Add("--null");
508 |
509 | // Effects.
510 | foreach (IBaseEffect effect in Effects)
511 | args.Add(effect.ToString());
512 |
513 | // Custom effects.
514 | args.Add(CustomEffects);
515 |
516 | soxProcess_.StartInfo.Arguments = String.Join(" ", args);
517 | LastCommand = Path + " " + soxProcess_.StartInfo.Arguments;
518 |
519 | try
520 | {
521 | soxProcess_.Start();
522 | soxProcess_.BeginOutputReadLine();
523 | soxProcess_.BeginErrorReadLine();
524 | soxProcess_.WaitForExit();
525 | }
526 |
527 | catch (Exception ex)
528 | {
529 | throw new SoxException("Cannot spawn SoX process", ex);
530 | }
531 |
532 | if (!String.IsNullOrEmpty(lastError_))
533 | {
534 | if (String.IsNullOrEmpty(lastErrorSource_))
535 | throw new SoxException(lastError_);
536 |
537 | switch (lastErrorSource_)
538 | {
539 | case "getopt":
540 | throw new SoxException("Invalid parameter: " + lastError_);
541 |
542 | default:
543 | throw new SoxException("Processing error: " + lastError_);
544 | }
545 | }
546 | }
547 |
548 | finally
549 | {
550 | if (soxProcess_ != null)
551 | {
552 | soxProcess_.Dispose();
553 | soxProcess_ = null;
554 | }
555 | }
556 | }
557 |
558 |
559 | private void OnSoxProcessOutputReceived(object sender, DataReceivedEventArgs received)
560 | {
561 | if (received.Data != null)
562 | {
563 | if (OnProgress != null)
564 | {
565 | Match matchProgress = SoxProcess.ProgressRegex.Match(received.Data);
566 |
567 | if (matchProgress.Success)
568 | {
569 | try
570 | {
571 | UInt16 progress = Convert.ToUInt16(double.Parse(matchProgress.Groups[1].Value, CultureInfo.InvariantCulture));
572 | TimeSpan processed = Utils.TimeSpanFromString(matchProgress.Groups[2].Value);
573 | TimeSpan remaining = Utils.TimeSpanFromString(matchProgress.Groups[3].Value);
574 | UInt64 outputSize = FormattedSize.ToUInt64(matchProgress.Groups[4].Value);
575 |
576 | ProgressEventArgs eventArgs = new ProgressEventArgs(progress, processed, remaining, outputSize);
577 | OnProgress(sender, eventArgs);
578 |
579 | if (eventArgs.Abort)
580 | Abort();
581 |
582 | return;
583 | }
584 |
585 | catch (Exception ex)
586 | {
587 | throw new SoxUnexpectedOutputException(received.Data, ex);
588 | }
589 | }
590 | }
591 |
592 | CheckForLogMessage(received.Data);
593 | }
594 | }
595 |
596 |
597 | ///
598 | /// Kills the SoX process.
599 | ///
600 | public void Abort()
601 | {
602 | if ((soxProcess_ != null) && !soxProcess_.HasExited)
603 | {
604 | try
605 | {
606 | soxProcess_.Kill();
607 | }
608 |
609 | finally
610 | {
611 | soxProcess_.Dispose();
612 | soxProcess_ = null;
613 | }
614 | }
615 | }
616 |
617 |
618 | private void CheckForLogMessage(string data)
619 | {
620 | if (string.IsNullOrEmpty(data))
621 | return;
622 |
623 | Match logMatch = SoxProcess.LogRegex.Match(data);
624 |
625 | if (logMatch.Success)
626 | {
627 | string logLevel = logMatch.Groups[1].Value;
628 | string source = logMatch.Groups[2].Value;
629 | string message = logMatch.Groups[3].Value;
630 |
631 | if ("DBUG".Equals(logLevel) && (OnLogMessage != null))
632 | OnLogMessage(this, new LogMessageEventArgs(LogLevelType.Debug, source, message));
633 |
634 | if ("INFO".Equals(logLevel) && (OnLogMessage != null))
635 | OnLogMessage(this, new LogMessageEventArgs(LogLevelType.Info, source, message));
636 |
637 | if ("WARN".Equals(logLevel) && (OnLogMessage != null))
638 | OnLogMessage(this, new LogMessageEventArgs(LogLevelType.Warning, source, message));
639 |
640 | else if ("FAIL".Equals(logLevel))
641 | {
642 | if (String.IsNullOrEmpty(lastError_))
643 | lastError_ = message;
644 |
645 | if (String.IsNullOrEmpty(lastErrorSource_))
646 | lastErrorSource_ = source;
647 | }
648 | }
649 | }
650 |
651 |
652 | protected virtual void Dispose(bool disposing)
653 | {
654 | if (disposed_)
655 | return;
656 |
657 | if (disposing)
658 | Abort();
659 |
660 | disposed_ = true;
661 | }
662 | }
663 | }
664 |
--------------------------------------------------------------------------------
/src/SoxProcess.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Text.RegularExpressions;
5 | using SoxSharp.Exceptions;
6 |
7 |
8 | namespace SoxSharp
9 | {
10 | internal sealed class SoxProcess : Process
11 | {
12 | public static readonly Regex InfoRegex = new Regex(@"Input File\s*: .+\r?\nChannels\s*: (\d+)\r?\nSample Rate\s*: (\d+)\r?\nPrecision\s*: ([\s\S]+?)\r?\nDuration\s*: (\d{2}:\d{2}:\d{2}\.?\d{2}?)[\s\S]+?\r?\nFile Size\s*: (\d+\.?\d{0,2}?[k|M|G]?)\r?\nBit Rate\s*: (\d+\.?\d{0,2}?[k|M|G]?)\r?\nSample Encoding\s*: (.+)");
13 | public static readonly Regex ProgressRegex = new Regex(@"In:(\d{1,3}\.?\d{0,2})%\s+(\d{2}:\d{2}:\d{2}\.?\d{0,2})\s+\[(\d{2}:\d{2}:\d{2}\.?\d{0,2})\]\s+Out:(\d+\.?\d{0,2}[k|M|G]?)");
14 | public static readonly Regex LogRegex = new Regex(@"(FAIL|WARN|DBUG|INFO)\s(\w+):\s(.+)");
15 |
16 |
17 | private SoxProcess()
18 | : base()
19 | {
20 | StartInfo.ErrorDialog = false;
21 | StartInfo.CreateNoWindow = true;
22 | StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
23 | StartInfo.UseShellExecute = false;
24 | StartInfo.RedirectStandardOutput = true;
25 | StartInfo.RedirectStandardError = true;
26 | EnableRaisingEvents = true;
27 | }
28 |
29 |
30 | ///
31 | /// Create a new instance prepared to run SoX.
32 | ///
33 | /// The SoX process instance.
34 | public static SoxProcess Create(string path)
35 | {
36 | string soxExecutable;
37 |
38 | if (String.IsNullOrEmpty(path))
39 | throw new SoxException("SoX path not specified");
40 |
41 | if (File.Exists(path))
42 | soxExecutable = path;
43 | else
44 | throw new FileNotFoundException("SoX executable not found");
45 |
46 | using (SoxProcess versionCheck = new SoxProcess())
47 | {
48 | versionCheck.StartInfo.RedirectStandardOutput = true;
49 | versionCheck.StartInfo.FileName = soxExecutable;
50 | versionCheck.StartInfo.Arguments = "--version";
51 | versionCheck.Start();
52 |
53 | string output = versionCheck.StandardOutput.ReadLine();
54 |
55 | if (versionCheck.WaitForExit(1000) == false)
56 | throw new TimeoutException("Cannot obtain SoX version: response timeout");
57 |
58 | Match versionMatch = new Regex(@"\sSoX v(\d{1,2})\.(\d{1,2})\.(\d{1,2})").Match(output);
59 |
60 | if (!versionMatch.Success)
61 | throw new SoxException("Cannot obtain SoX version: unable to fetch info from Sox");
62 |
63 | try
64 | {
65 | int majorVersion = Int32.Parse(versionMatch.Groups[1].Value);
66 | int minorVersion = Int32.Parse(versionMatch.Groups[2].Value);
67 | int fixVersion = Int32.Parse(versionMatch.Groups[3].Value);
68 |
69 | if ((majorVersion < 14) ||
70 | ((majorVersion == 14) && (minorVersion < 3)) ||
71 | ((majorVersion == 14) && (minorVersion == 3) && (fixVersion < 1)))
72 | throw new SoxException(versionMatch.Groups[0] + " not currently supported");
73 | }
74 |
75 | catch (Exception ex)
76 | {
77 | throw new SoxException("Cannot obtain SoX version", ex);
78 | }
79 | }
80 |
81 | SoxProcess soxProc = new SoxProcess();
82 | soxProc.StartInfo.FileName = soxExecutable;
83 | soxProc.StartInfo.WorkingDirectory = Environment.CurrentDirectory;
84 |
85 | string soxPath = Path.GetDirectoryName(soxExecutable);
86 |
87 | if (!String.IsNullOrEmpty(soxPath))
88 | {
89 | string pathEnv = Environment.GetEnvironmentVariable("PATH");
90 | pathEnv += Path.PathSeparator + soxPath;
91 | soxProc.StartInfo.EnvironmentVariables["PATH"] = pathEnv;
92 | }
93 |
94 | return soxProc;
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/SoxSharp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0;net45
5 | latest
6 | true
7 | 1.3.5
8 | igece.labs
9 |
10 | https://github.com/igece/SoxSharp
11 | https://github.com/igece/SoxSharp
12 | Library that serves as a wrapper to SoX - the Sound eXchange tool.
13 | sox wrapper audio conversion filters
14 | Added compatibility with .NET Standard
15 | LICENSE
16 |
17 |
18 |
19 | true
20 | ..\bin\$(Configuration)
21 |
22 |
23 |
24 | ..\bin\$(Configuration)
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | True
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/SoxSharp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27428.2015
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SoxSharp", "SoxSharp.csproj", "{900A3274-0A8A-4AF3-A34F-CCB27114E58F}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {900A3274-0A8A-4AF3-A34F-CCB27114E58F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {900A3274-0A8A-4AF3-A34F-CCB27114E58F}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {900A3274-0A8A-4AF3-A34F-CCB27114E58F}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {900A3274-0A8A-4AF3-A34F-CCB27114E58F}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {6B877572-083E-4CE5-9EAE-69D95ACCFDEB}
24 | EndGlobalSection
25 | GlobalSection(MonoDevelopProperties) = preSolution
26 | Policies = $0
27 | $0.DotNetNamingPolicy = $1
28 | $1.DirectoryNamespaceAssociation = PrefixedFlat
29 | $0.StandardHeader = $2
30 | version = 1.2.*
31 | EndGlobalSection
32 | EndGlobal
33 |
--------------------------------------------------------------------------------
/src/Types.cs:
--------------------------------------------------------------------------------
1 | namespace SoxSharp
2 | {
3 | ///
4 | /// Audio file formats.
5 | ///
6 | public enum FileType
7 | {
8 | ///
9 | /// Amiga 8SVX musical instrument description format.
10 | ///
11 | SVX,
12 |
13 | ///
14 | /// Audio Interchage File Format. Used on old Apple Macs, Apple IIc/IIgs and SGI. SoX’s AIFF support does not
15 | /// include multiple audio chunks, or the 8SVX musical instrument description format. AIFF files are multimedia
16 | /// archives and can have multiple audio and picture chunks — you may need a separate archiver to work with them.
17 | /// With Mac OS X, AIFF has been superseded by CAF.
18 | ///
19 | AIF,
20 |
21 | ///
22 | /// AIFF-C (not compressed), defined in DAVIC 1.4 Part 9 Annex B. Format based on AIFF that was created to allow
23 | /// handling compressed audio. It can also handle little endian uncompressed linear data that is often referred to
24 | /// as sowt encoding. This encoding has also become the defacto format produced by modern Macs as well as iTunes on
25 | /// any platform. AIFF-C files produced by other applications typically have the file extension .aif and require
26 | /// looking at its header to detect the true format. The sowt encoding is the only encoding that SoX can handle
27 | /// with this format. Any private chunks are not supported.
28 | ///
29 | AIFC,
30 |
31 | ///
32 | /// Audio Interchage File Format. Used on old Apple Macs, Apple IIc/IIgs and SGI. SoX’s AIFF support does not
33 | /// include multiple audio chunks, or the 8SVX musical instrument description format. AIFF files are multimedia
34 | /// archives and can have multiple audio and picture chunks — you may need a separate archiver to work with them.
35 | /// With Mac OS X, AIFF has been superseded by CAF.
36 | ///
37 | AIFF,
38 |
39 | ///
40 | /// AIFF-C (not compressed), defined in DAVIC 1.4 Part 9 Annex B. Format based on AIFF that was created to allow
41 | /// handling compressed audio. It can also handle little endian uncompressed linear data that is often referred to
42 | /// as sowt encoding. This encoding has also become the defacto format produced by modern Macs as well as iTunes on
43 | /// any platform. AIFF-C files produced by other applications typically have the file extension .aif and require
44 | /// looking at its header to detect the true format. The sowt encoding is the only encoding that SoX can handle
45 | /// with this format. Any private chunks are not supported.
46 | ///
47 | AIFFC,
48 |
49 | ///
50 | /// Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 8-bit A-law.
51 | ///
52 | AL,
53 |
54 | ///
55 | /// Ambisonic B‐Format. A specialisation of .wav with between 3 and 16 channels of audio for use with an Ambisonic
56 | /// decoder. It is up to the user to get the channels together in the right order and at the correct amplitude.
57 | ///
58 | AMB,
59 |
60 | ///
61 | /// Sun Microsystems AU file.
62 | ///
63 | AU,
64 |
65 | ///
66 | /// Audio Visual Research format; used by a number of commercial packages on the Mac.
67 | ///
68 | AVR,
69 |
70 | ///
71 | /// Apple’s Core Audio File format.
72 | ///
73 | CAF,
74 |
75 | ///
76 | /// ‘Red Book’ Compact Disc Digital Audio (raw audio). CDDA has two audio channels formatted as 16-bit signed
77 | /// integers (big endian)at a sample rate of 44.1 kHz. The number of (stereo) samples in each CDDA track is always
78 | /// a multiple of 588.
79 | ///
80 | CDDA,
81 |
82 | ///
83 | /// ‘Red Book’ Compact Disc Digital Audio (raw audio). CDDA has two audio channels formatted as 16-bit signed
84 | /// integers (big endian)at a sample rate of 44.1 kHz. The number of (stereo) samples in each CDDA track is always
85 | /// a multiple of 588.
86 | ///
87 | CDR,
88 |
89 | ///
90 | /// Headerless MIL Std 188 113 Continuously Variable Slope Delta modulation. A headerless format used to compress
91 | /// speech audio for applications such as voice mail. This format is sometimes used with bit-reversed samples.
92 | ///
93 | CVS,
94 |
95 | ///
96 | /// Headerless MIL Std 188 113 Continuously Variable Slope Delta modulation. A headerless format used to compress
97 | /// speech audio for applications such as voice mail. This format is sometimes used with bit-reversed samples.
98 | ///
99 | CVSD,
100 |
101 | ///
102 | /// Headerless Continuously Variable Slope Delta modulation (unfiltered). This is an alternative handler for CVSD
103 | /// that is unfiltered but can be used with any bit-rate.
104 | ///
105 | CVU,
106 |
107 | ///
108 | /// Text Data files. These files contain a textual representation of the sample data. There is one line at the
109 | /// beginning that contains the sample rate, and one line that contains the number of channels. Subsequent lines
110 | /// contain two or more numeric data intems: the time since the beginning of the first sample and the sample value
111 | /// for each channel.
112 | ///
113 | DAT,
114 |
115 | ///
116 | /// Self-describing variant of CVSD.
117 | ///
118 | DVMS,
119 |
120 | ///
121 | /// Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 32-bit floating point PCM.
122 | ///
123 | F32,
124 |
125 | ///
126 | /// [DEPRECATED] Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 4 bytes floating point PCM.
127 | /// Superseded by F32 type.
128 | ///
129 | F4,
130 |
131 | ///
132 | /// Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 64-bit floating point PCM.
133 | ///
134 | F64,
135 |
136 | ///
137 | /// [DEPRECATED] Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 8 bytes floating point PCM.
138 | /// Superseded by F64 type.
139 | ///
140 | F8,
141 |
142 | ///
143 | /// Ensoniq PARIS file format (little-endian).
144 | ///
145 | FAP,
146 |
147 | ///
148 | /// Xiph.org’s Free Lossless Audio Codec Compressed Audio. Open, patent-free codec designed for compressing music.
149 | /// SoX can read native FLAC files (.flac) but not Ogg FLAC files (.ogg).
150 | /// SoX can write native FLAC files according to a given or default compression level
151 | /// (see ). 8 is the default compression level and gives the best
152 | /// (but slowest) compression; 0 gives the least (but fastest) compression.
153 | ///
154 | FLAC,
155 |
156 | ///
157 | /// An alias for the .u8 format.
158 | ///
159 | FSSD,
160 |
161 | ///
162 | /// GSM 06.10 Lossy Speech Compression. A lossy format for compressing speech which is used in the Global Standard
163 | /// for Mobile telecommunications (GSM). It’s good for its purpose, shrinking audio data size, but it will introduce
164 | /// lots of noise when a given audio signal is encoded and decoded multiple times. This format is used by some voice
165 | /// mail applications. It is rather CPU intensive.
166 | ///
167 | GSM,
168 |
169 | ///
170 | /// Grandstream ringtone files. Whilst this file format can contain A-Law, μ-law, GSM, G.722, G.723, G.726, G.728, or iLBC
171 | /// encoded audio, SoX supports reading and writing only A-Law and μ-law.
172 | ///
173 | GSRT,
174 |
175 | ///
176 | /// Macintosh HCOM files. These are Mac FSSD files with Huffman compression.
177 | ///
178 | HCOM,
179 |
180 | ///
181 | /// Single channel 16-bit PCM format used by HTK, a toolkit for building Hidden Markov Model speech processing tools.
182 | ///
183 | HTK,
184 |
185 | ///
186 | /// A headerless file of IMA ADPCM audio data. IMA ADPCM claims 16-bit precision packed into only 4 bits, but in fact
187 | /// sounds no better than .vox.
188 | ///
189 | IMA,
190 |
191 | ///
192 | /// Another name for SF.
193 | ///
194 | IRCAM,
195 |
196 | ///
197 | /// Raw (headerless) audio file with a default sample rate of 8kHz and encoded as inverse bit order 8-bit A-law.
198 | ///
199 | LA,
200 |
201 | ///
202 | /// LPC-10 is a compression scheme for speech developed in the United States. See http://www.arl.wustl.edu/˜jaf/lpc/
203 | /// for details. There is no associated file format, so SoX’s implementation is headerless.
204 | ///
205 | LPC,
206 |
207 | ///
208 | /// LPC-10 is a compression scheme for speech developed in the United States. See http://www.arl.wustl.edu/˜jaf/lpc/
209 | /// for details. There is no associated file format, so SoX’s implementation is headerless.
210 | ///
211 | LPC10,
212 |
213 | ///
214 | /// Raw (headerless) audio file with a default sample rate of 8kHz and encoded as inverse bit order 8-bit μ-law.
215 | ///
216 | LU,
217 |
218 | ///
219 | /// An IFF-conforming audio file type, registered by MS MacroSystem Computer GmbH, published along with the ‘Toccata’
220 | /// soundcard on the Amiga. Allows 8-bit linear, 16-bit linear, A-Law, μ-law in mono and stereo.
221 | ///
222 | MAUD,
223 |
224 | MP2,
225 |
226 | ///
227 | /// MP3 compressed audio; MP3 (MPEG Layer 3) is a part of the MPEG standards for audio and video compression. It is a
228 | /// lossy compression format that achieves good compression rates with little quality loss.
229 | ///
230 | MP3,
231 |
232 | ///
233 | /// SPHERE (SPeech HEader Resources). Format defined by NIST (National Institute of Standards and Technology) and
234 | /// used with speech audio. SoX can read these files when they contain μ-law and PCM data. It will ignore any header
235 | /// information that says the data is compressed using shorten compression and will treat the data as either μ-law
236 | /// or PCM.
237 | ///
238 | NIST,
239 |
240 | PRC,
241 |
242 | ///
243 | /// Raw (headerless) audio file.
244 | ///
245 | RAW,
246 |
247 | ///
248 | /// [DEPRECATED] Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 1 byte signed integer PCM.
249 | /// Superseded by S8 type.
250 | /// ///
251 | S1,
252 |
253 | ///
254 | /// Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 16-bit signed integer PCM.
255 | ///
256 | S16,
257 |
258 | ///
259 | /// [DEPRECATED] Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 2 bytes signed integer PCM.
260 | /// Superseded by S16 type.
261 | ///
262 | S2,
263 |
264 | ///
265 | /// Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 24-bit signed integer PCM.
266 | ///
267 | S24,
268 |
269 | ///
270 | /// [DEPRECATED] Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 3 bytes signed integer PCM.
271 | /// Superseded by S24 type.
272 | ///
273 | S3,
274 |
275 | ///
276 | /// Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 32-bit signed integer PCM.
277 | ///
278 | S32,
279 |
280 | ///
281 | /// [DEPRECATED] Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 4 bytes signed integer PCM.
282 | /// Superseded by S32 type.
283 | ///
284 | S4,
285 |
286 | ///
287 | /// Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 8-bit signed integer PCM.
288 | ///
289 | S8,
290 |
291 | ///
292 | /// [DEPRECATED] Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 1 byte signed integer PCM.
293 | /// Superseded by S8 type.
294 | ///
295 | SB,
296 |
297 | SF,
298 |
299 | ///
300 | /// [DEPRECATED] Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 4 bytes signed integer PCM.
301 | /// Superseded by S32 type.
302 | ///
303 | SL,
304 |
305 | SMP,
306 | SND,
307 | SNDR,
308 | SNDT,
309 | SOU,
310 | SOX,
311 |
312 | ///
313 | /// SPHERE (SPeech HEader Resources). Format defined by NIST (National Institute of Standards and Technology) and
314 | /// used with speech audio. SoX can read these files when they contain μ-law and PCM data. It will ignore any header
315 | /// information that says the data is compressed using shorten compression and will treat the data as either μ-law
316 | /// or PCM.
317 | ///
318 | SPH,
319 |
320 | ///
321 | /// [DEPRECATED] Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 2 bytes signed integer PCM.
322 | /// Superseded by S16 type.
323 | ///
324 | SW,
325 |
326 | TXW,
327 |
328 | ///
329 | /// [DEPRECATED] Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 1 byte unsigned integer PCM.
330 | /// Superseded by U8 type.
331 | ///
332 | U1,
333 |
334 | ///
335 | /// Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 16-bit unsigned integer PCM.
336 | ///
337 | U16,
338 |
339 | ///
340 | /// [DEPRECATED] Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 2 bytes unsigned integer PCM.
341 | /// Superseded by U16 type.
342 | ///
343 | U2,
344 |
345 | ///
346 | /// Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 24-bit unsigned integer PCM.
347 | ///
348 | U24,
349 |
350 | ///
351 | /// [DEPRECATED] Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 3 bytes unsigned integer PCM.
352 | /// Superseded by U24 type.
353 | ///
354 | U3,
355 |
356 | ///
357 | /// Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 32-bit unsigned integer PCM.
358 | ///
359 | U32,
360 |
361 | ///
362 | /// [DEPRECATED] Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 4 bytes unsigned integer PCM.
363 | /// Superseded by U32 type.
364 | ///
365 | U4,
366 |
367 | ///
368 | /// Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 8-bit unsigned integer PCM.
369 | ///
370 | U8,
371 |
372 | ///
373 | /// [DEPRECATED] Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 1 byte unsigned integer PCM.
374 | /// Superseded by U8 type.
375 | ///
376 | UB,
377 |
378 | ///
379 | /// Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 8-bit μ-law.
380 | ///
381 | UL,
382 |
383 | ///
384 | /// [DEPRECATED] Raw (headerless) audio file with a default sample rate of 8kHz and encoded as 2 bytes unsigned integer PCM.
385 | /// Superseded by S16 type.
386 | ///
387 | UW,
388 |
389 | ///
390 | /// Self-describing variant of CVSD.
391 | ///
392 | VMS,
393 |
394 | ///
395 | /// Sound Blaster VOC files. VOC files are multi-part and contain silence parts, looping, and different sample rates
396 | /// for different chunks. On input, the silence parts are filled out, loops are rejected, and sample data with a new
397 | /// sample rate is rejected. Silence with a different sample rate is generated appropriately. On output, silence is
398 | /// not detected, nor are impossible sample rates. SoX supports reading (but not writing) VOC files with multiple
399 | /// blocks, and files containing μ-law, A-law, and 2/3/4-bit ADPCM samples.
400 | ///
401 | VOC,
402 |
403 | ///
404 | /// A headerless file of Dialogic/OKI ADPCM audio data. This ADPCM data has 12-bit precision packed into only 4-bits.
405 | /// Some early Dialogic hardware does not always reset the ADPCM encoder at the start of each vox file. This can
406 | /// result in clipping and/or DC offset problems when it comes to decoding the audio. Whilst little can be done
407 | /// about the clipping, a DC offset can be removed by passing the decoded audio through a high-pass filter.
408 | ///
409 | VOX,
410 |
411 | ///
412 | /// Microsoft .WAV RIFF files. This is the native audio file format of Windows, and widely used for uncompressed
413 | /// audio. Normally .wav files have all formatting information in their headers, and so do not need any format
414 | /// options specified for an input file. If any are, they will override the file header, and you will be warned to
415 | /// this effect. Output format options will cause a format conversion, and the .wav will written appropriately.
416 | /// SoX can read and write linear PCM, floating point, μ-law, A-law, MS ADPCM, and IMA (or DVI) ADPCM encoded
417 | /// samples. WAV files can also contain audio encoded in many other ways (not currently supported with SoX)
418 | /// e.g. MP3; in some cases such a file can still be read by SoX by overriding the file type. Big endian versions
419 | /// of RIFF files, called RIFX, are also supported.
420 | ///
421 | WAV,
422 |
423 | ///
424 | /// A non-standard, but widely used, variant of .wav. Some applications cannot read a standard WAV file header for
425 | /// PCM-encoded data with sample-size greater than 16-bits or with more than two channels, but can read a non-
426 | /// standard WAV header. It is likely that such applications will eventually be updated to support the standard
427 | /// header, but in the mean time, this SoX format can be used to create files with the non-standard header that
428 | /// should work with these applications. Note that SoX will automatically detect and read WAV files with the
429 | /// non-standard header.
430 | ///
431 | WAVPCM,
432 |
433 | ///
434 | /// Psion 8-bit A-law. Used on Psion SIBO PDAs (Series 3 and similar). This format is deprecated in SoX, but will
435 | /// continue to be used in libsndfile.
436 | ///
437 | WVE,
438 |
439 | ///
440 | /// Maxis XA files. These are 16-bit ADPCM audio files used by Maxis games. Writing .xa files is currently not
441 | /// supported.
442 | ///
443 | XA
444 | }
445 |
446 | ///
447 | /// Encoding type.
448 | ///
449 | public enum EncodingType
450 | {
451 | SignedInteger,
452 | UnsignedInteger,
453 | FloatingPoint,
454 | MuLaw,
455 | ALaw,
456 | ImaAdpcm,
457 | MsAdpcm,
458 | GsmFullRate
459 | }
460 |
461 |
462 | ///
463 | /// Byte order type.
464 | ///
465 | public enum ByteOrderType
466 | {
467 | ///
468 | /// Big endian byte order.
469 | ///
470 | BigEndian,
471 |
472 | ///
473 | /// Little endian byte order.
474 | ///
475 | LittleEndian,
476 |
477 | ///
478 | /// Swap the current byte order.
479 | ///
480 | Swap
481 | }
482 |
483 |
484 | ///
485 | /// SoX log message level.
486 | ///
487 | public enum LogLevelType
488 | {
489 | ///
490 | /// Warning message.
491 | ///
492 | Warning,
493 |
494 | ///
495 | /// Information message.
496 | ///
497 | Info,
498 |
499 | ///
500 | /// Debug message.
501 | ///
502 | Debug
503 | }
504 |
505 |
506 | ///
507 | /// How SoX’s input combiner shall combine multiple input files.
508 | ///
509 | public enum CombinationType
510 | {
511 | ///
512 | /// Use the default combination type ( for Process and Record
513 | /// and for Play).
514 | ///
515 | Default,
516 |
517 | ///
518 | /// Concatenate all input files (the default for process and record).
519 | /// Input files must have the same number of channels. The audio from each input will be concatenated
520 | /// in the order given to form the output file.
521 | ///
522 | Concatenate,
523 |
524 | ///
525 | /// Merge multiple input files.
526 | /// The number of channels in each input file need not be the same. A merged audio file comprises all
527 | /// of the channels from all of the input files. For example, two mono files could be merged to form
528 | /// one stereo file. The first and second mono files would become the left and right channels of the
529 | /// stereo file. Un-merging is possible using multiple invocations of SoX with the remix effect.
530 | ///
531 | Merge,
532 |
533 | ///
534 | /// Mix multiple input files.
535 | /// The number of channels in each input file need not be the same, but SoX will issue a warning if they
536 | /// are not and some channels in the output file will not contain audio from every input file. A mixed
537 | /// audio file cannot be un-mixed without reference to the original input files.
538 | ///
539 | Mix,
540 |
541 | ///
542 | /// Mix to equal power multiple input files.
543 | ///
544 | MixPower,
545 |
546 | ///
547 | /// Multiply samples of corresponding channels from all input files.
548 | /// Sample values of corresponding channels are treated as numbers in the interval −1 to +1. If the
549 | /// number of channels in the input files is not the same, the missing channels are considered
550 | /// to contain all zero.
551 | ///
552 | Multiply,
553 |
554 | ///
555 | /// Sequence all input files (the default for play).
556 | /// It is similar to in that the audio from each input file
557 | /// is sent serially to the output file. However, here the output file may be closed and reopened at
558 | /// the corresponding transition between input files.
559 | ///
560 | Sequence
561 | }
562 | }
563 |
--------------------------------------------------------------------------------
/src/Utils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Linq;
4 |
5 |
6 | namespace SoxSharp
7 | {
8 | static class Utils
9 | {
10 | private static int[] weights2 = { 60, 1 };
11 | private static int[] weights3 = { 60 * 60, 60, 1 };
12 |
13 |
14 | public static TimeSpan TimeSpanFromString(string time)
15 | {
16 | string[] parts = time.Split(':');
17 |
18 | switch (parts.Length)
19 | {
20 | case 1:
21 | return TimeSpan.FromSeconds(Convert.ToDouble(parts[0], CultureInfo.InvariantCulture));
22 |
23 | case 2:
24 | return TimeSpan.FromSeconds(parts.Zip(weights2, (d, w) => String.IsNullOrEmpty(d) ? 0 : Convert.ToDouble(d, CultureInfo.InvariantCulture) * w).Sum());
25 |
26 | case 3:
27 | return TimeSpan.FromSeconds(parts.Zip(weights3, (d, w) => String.IsNullOrEmpty(d) ? 0 : Convert.ToDouble(d, CultureInfo.InvariantCulture) * w).Sum());
28 |
29 | default:
30 |
31 | throw new ArgumentException("Invalid time string");
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------