-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathMP3.html
143 lines (143 loc) · 10.3 KB
/
MP3.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Content-Style-Type" content="text/css">
<title></title>
<meta name="Generator" content="Cocoa HTML Writer">
<meta name="CocoaVersion" content="824.41">
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Helvetica}
p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px}
p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica}
p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; color: #9b1e12}
p.p5 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; color: #9b1e12}
p.p6 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco}
p.p7 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; color: #0029b3}
p.p8 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; min-height: 12.0px}
p.p9 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; color: #606060}
span.s1 {color: #0029b3}
span.s2 {color: #2c7014}
span.s3 {color: #000000}
span.s4 {color: #606060}
span.s5 {color: #416d1f}
span.Apple-tab-span {white-space:pre}
</style>
</head>
<body>
<p class="p1"><b>MP3<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>Read an MP3 file or stream, or write an MP3 file <i>(can also read Ogg)</i></b></p>
<p class="p2"><br></p>
<p class="p3">This class is a wrapper for the *nix command-line tools <b>curl</b> and <b>lame</b>, making it easy to access MP3 files and MP3 (shoutcast/icecast) internet streams. This implies two caveats:</p>
<p class="p2"><br></p>
<p class="p3"><span class="Apple-converted-space"> </span>* It will work on Mac OSX, Linux, and other unix-like systems, but is <i>extremely</i> unlikely to work on Windows.</p>
<p class="p3"><span class="Apple-converted-space"> </span>* You must have curl and lame installed on your system. <b>curl</b> is a generic tool for internet downloading, and is available on most systems. <b>lame</b> is a tool commonly used for MP3 encoding/decoding.</p>
<p class="p2"><br></p>
<p class="p3">To tell this class where your system's lame and curl programs are, you can check/set the class variables (you could add a line to your startup file to set them):</p>
<p class="p2"><br></p>
<p class="p3"><span class="s1">MP3</span>.lamepath;</p>
<p class="p3"><span class="s1">MP3</span>.curlpath;</p>
<p class="p4">// To check that there's a file at the expected path</p>
<p class="p3"><span class="s1">File</span>.exists(<span class="s1">MP3</span>.lamepath)</p>
<p class="p3"><span class="s1">File</span>.exists(<span class="s1">MP3</span>.curlpath)</p>
<p class="p2"><br></p>
<p class="p3">In order to use this class you create an instance of it, passing a path or URL to the MP3 data as the first argument. The second constructor argument is the mode, either <span class="s2">\readfile</span> to read from a file (this is the default), or <span class="s2">\readurl</span> to read from a URL, or <span class="s2">\writefile</span> to write to a file. You can then call the <b>start</b> method when you want the MP3 data to begin queueing up (i.e. before you start your SC DiskIn/DiskOut synth or whatever). You then use the <b>fifo</b> variable as the path to stream into the buffer.</p>
<p class="p2"><br></p>
<p class="p3">Additional arguments can be passed to the lame executable, passed in as a string as the first argument to .start.</p>
<p class="p2"><br></p>
<p class="p3">For file writing, the class tells lame to expect <i>16-bit raw audio data at 44.1 kHz</i>, so this is what you must output - see the example below. (The reason for writing as raw data is that the "fifo" trick excludes the possibility of the fileseeking which is required for writing soundfile headers.)</p>
<p class="p2"><br></p>
<p class="p3">The .<b>playing</b> flag can tell you whether the MP3 is currently (still) playing - i.e. it is true if you have started the MP3 and not yet stopped it. (It will revert back to false if the MP3 file finishes, even if you haven't called the .stop method.)</p>
<p class="p2"><br></p>
<p class="p3"><b>Ogg format files</b> can be read (despite the name of the class!) as long as you have the <b>oggdec</b> command-line tool installed. To tell the class that it should expect an ogg file rather than an MP3, set the constructor's "format" argument (the third argument) to <span class="s2">\ogg</span> .</p>
<p class="p2"><br></p>
<p class="p3"><b>Examples</b></p>
<p class="p2"><br></p>
<p class="p5">// Let's read in an internet radio stream and warp it a bit.</p>
<p class="p5">// First we need a synthdef:</p>
<p class="p6">s.boot;</p>
<p class="p6">(</p>
<p class="p7">SynthDef<span class="s3">(</span><span class="s4">"help_mp3_01"</span><span class="s3">, { </span>|bufnum = 0|</p>
<p class="p6"><span class="Apple-tab-span"> </span><span class="s1">var</span> son, wibble;</p>
<p class="p6"><span class="Apple-tab-span"> </span>son = <span class="s1">DiskIn</span>.ar(2, bufnum);</p>
<p class="p6"><span class="Apple-tab-span"> </span>wibble = <span class="s1">LFPar</span>.kr(0.1).range(0.5, 2.0);</p>
<p class="p6"><span class="Apple-tab-span"> </span>son = <span class="s1">PitchShift</span>.ar(son, pitchRatio: wibble);</p>
<p class="p6"><span class="Apple-tab-span"> </span><span class="s1">Out</span>.ar(0, son);</p>
<p class="p6">}).load(s);</p>
<p class="p6">)</p>
<p class="p8"><br></p>
<p class="p5">// Now let's create the MP3 object and cue it into a Buffer.</p>
<p class="p8"><br></p>
<p class="p5">// Choose one of these two:</p>
<p class="p5">// (a) a stream URL - note the use of the second argument to indicate a remote stream</p>
<p class="p9"><span class="s3">m = </span><span class="s1">MP3</span><span class="s3">(</span>"http://icecast.commedia.org.uk:8000/resonance.mp3"<span class="s3">, </span><span class="s5">\readurl</span><span class="s3">);</span></p>
<p class="p5">// (b) a local file</p>
<p class="p9"><span class="s3">m = </span><span class="s1">MP3</span><span class="s3">(</span>"/Users/dan/Music/SqueezeTheTrigger(Version1).mp3"<span class="s3">);</span></p>
<p class="p9"><span class="s3">m = </span><span class="s1">MP3</span><span class="s3">(</span>"/Users/danstowell/Music/ManiAyer.mp3"<span class="s3">);</span></p>
<p class="p8"><br></p>
<p class="p6">m.start;</p>
<p class="p5">// Now you can use it almost like any other file, by reading from m.fifo</p>
<p class="p6">b = <span class="s1">Buffer</span>.cueSoundFile(s, m.fifo, 0, 2);</p>
<p class="p6">x = <span class="s1">Synth</span>(<span class="s4">"help_mp3_01"</span>, [<span class="s5">\bufnum</span>, b.bufnum], addAction:<span class="s5">\addToTail</span>);</p>
<p class="p6">m.playing;</p>
<p class="p5">// You can stop and restart the piping (with a bit of a delay) - note what happens</p>
<p class="p6">m.stop;</p>
<p class="p6">m.playing;</p>
<p class="p6">m.start;</p>
<p class="p6">m.playing;</p>
<p class="p5">// Please remember to tidy up after yourself:</p>
<p class="p6">x.free;</p>
<p class="p6">b.close; b.free;</p>
<p class="p6">m.finish;</p>
<p class="p8"><br></p>
<p class="p8"><br></p>
<p class="p5">/////////////////////////////////////////////////////</p>
<p class="p8"><br></p>
<p class="p5">// Reading into a buffer is possible, but you *must* specify the number of (uncompressed) frames to read.</p>
<p class="p9"><span class="s3">m = </span><span class="s1">MP3</span><span class="s3">(</span>"http://icecast.commedia.org.uk:8000/resonance.mp3"<span class="s3">, </span><span class="s5">\readurl</span><span class="s3">);</span></p>
<p class="p6">m.start;</p>
<p class="p6">b= <span class="s1">Buffer</span>.read(s, m.fifo, 0, 50000);</p>
<p class="p5">// After a second or two, should be able to play a snatch of the stream</p>
<p class="p6">b.play;</p>
<p class="p8"><br></p>
<p class="p5">// Please remember to tidy up after yourself:</p>
<p class="p6">b.close; b.free;</p>
<p class="p6">m.finish;</p>
<p class="p8"><br></p>
<p class="p8"><br></p>
<p class="p5">/////////////////////////////////////////////////////</p>
<p class="p8"><br></p>
<p class="p5">// Alternatively, a method is provided for reading a local MP3 file more easily (won't work on streams)</p>
<p class="p6">s.boot;</p>
<p class="p9"><span class="s3">b = </span><span class="s1">MP3</span><span class="s3">.readToBuffer(s, </span>"/Users/dan/Music/SqueezeTheTrigger(Version1).mp3"<span class="s3">)</span></p>
<p class="p6">b.play;</p>
<p class="p8"><br></p>
<p class="p6">b.free;</p>
<p class="p8"><br></p>
<p class="p8"><br></p>
<p class="p5">/////////////////////////////////////////////////////</p>
<p class="p8"><br></p>
<p class="p5">// Writing an MP3 file using DiskOut. See the DiskOut helpfile for more on this.</p>
<p class="p6">(</p>
<p class="p7">SynthDef<span class="s3">(</span><span class="s4">"help_mp3_02"</span><span class="s3">, { </span>|bufnum = 0|</p>
<p class="p6"><span class="Apple-tab-span"> </span><span class="s1">var</span> son;</p>
<p class="p6"><span class="Apple-tab-span"> </span>son = <span class="s1">SinOsc</span>.ar(<span class="s1">SinOsc</span>.ar(<span class="s1">Line</span>.kr(1, 100, 10, doneAction:2)).range(220, 550)) * 0.1;</p>
<p class="p6"><span class="Apple-tab-span"> </span>son = son.dup;</p>
<p class="p6"><span class="Apple-tab-span"> </span><span class="s1">Out</span>.ar(0, son);</p>
<p class="p6"><span class="Apple-tab-span"> </span><span class="s1">DiskOut</span>.ar(bufnum, son);</p>
<p class="p6">}).load(s);</p>
<p class="p6">)</p>
<p class="p5">// Create an MP3 object for writing</p>
<p class="p9"><span class="s3">m = </span><span class="s1">MP3</span><span class="s3">(</span>"recordings/mp3test.mp3"<span class="s3">, </span><span class="s5">\writefile</span><span class="s3">);</span></p>
<p class="p6">m.start;</p>
<p class="p5">// allocate a disk i/o buffer</p>
<p class="p6">b = <span class="s1">Buffer</span>.alloc(s, 65536, 2);</p>
<p class="p5">// Start writing</p>
<p class="p6">b.write(m.fifo, <span class="s4">"raw"</span>, <span class="s4">"int16"</span>, 0, 0, <span class="s1">true</span>);</p>
<p class="p8"><br></p>
<p class="p6">x = <span class="s1">Synth</span>(<span class="s4">"help_mp3_02"</span>, [<span class="s5">\bufnum</span>, b.bufnum], addAction:<span class="s5">\addToTail</span>);</p>
<p class="p8"><br></p>
<p class="p5">// once the writing has stopped, tidy up</p>
<p class="p6">b.close; b.free;</p>
<p class="p6">m.finish;</p>
</body>
</html>