001/* A simple application that demonstrates the use of LiveSound by performing
002 simple additive synthesis in real-time.
003
004 Copyright (c) 2000-2014 The Regents of the University of California.
005 All rights reserved.
006 Permission is hereby granted, without written agreement and without
007 license or royalty fees, to use, copy, modify, and distribute this
008 software and its documentation for any purpose, provided that the above
009 copyright notice and the following two paragraphs appear in all copies
010 of this software.
011
012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016 SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023 ENHANCEMENTS, OR MODIFICATIONS.
024
025 PT_COPYRIGHT_VERSION_2
026 COPYRIGHTENDKEY
027
028 */
029package ptolemy.media.javasound.demo.LiveSines;
030
031import java.io.IOException;
032
033import ptolemy.actor.injection.ActorModuleInitializer;
034import ptolemy.media.javasound.LiveSound;
035
036////////////////////////////////////////////////////
037
038/**
039 A simple application that demonstrates the use of LiveSound.  This
040 application synthesizes and plays a simple harmonic signal, using simple
041 additive synthesis. The signal is the sum of a few harmonically related
042 sinusoids.
043
044 @author Brian K. Vogel, Neil E. Turner
045 @version $Id$
046 @since Ptolemy II 3.1
047 @Pt.ProposedRating Red (vogel)
048 @Pt.AcceptedRating Red (vogel)
049 */
050public class LiveSines {
051    /** Play a simple harmonic signal.
052     *  @param args Ignored.
053     */
054    public static void main(String[] args) {
055        ActorModuleInitializer.initializeInjector();
056
057        // The pitch of the signal to synthesize.
058        double fundamental1_Hz = 220;
059
060        // The pitch of the signal to synthesize.
061        double fundamental2_Hz = 220 * 1.5;
062
063        int sampleRate = 44100; // in Hz
064        int sampleSizeInBits = 16;
065        int channels = 2; // stereo.
066        int outBufferSize = 4096; // Internal buffer size for playback.
067
068        // Amount of data to read or write from/to the internal buffer
069        // at a time. This should be set smaller than the internal buffer
070        // size!
071        int putSamplesSize = 25;
072
073        try {
074            LiveSound.setSampleRate(sampleRate);
075            LiveSound.setChannels(channels);
076            System.out.println("Attempting to set playback buffer size: "
077                    + outBufferSize + " samples.");
078            LiveSound.setBufferSize(outBufferSize);
079            LiveSound.setBitsPerSample(sampleSizeInBits);
080            LiveSound.setTransferSize(putSamplesSize);
081
082            // Begin playback.
083            LiveSound.startPlayback(_producer);
084        } catch (IOException ex) {
085            System.err.println(ex);
086        }
087
088        double[][] samplesArray = new double[channels][putSamplesSize];
089
090        // keep track of time, used in calculating the sine wave values.
091        double[] samples = new double[channels];
092
093        System.out.println("                           Actual size: "
094                + LiveSound.getBufferSizePlayback() + " samples.");
095
096        try {
097            int channelNumber;
098
099            // Loop forever.
100            while (true) {
101                for (int i = 0; i < putSamplesSize; i++) {
102                    channelNumber = 0; //Left channel.
103
104                    // Generate a harmonic signal.
105                    samplesArray[channelNumber][i] = Math
106                            .sin(fundamental1_Hz * 2 * Math.PI
107                                    * samples[channelNumber])
108                            * 0.1
109                            + Math.sin(2 * fundamental1_Hz * 2 * Math.PI
110                                    * samples[channelNumber]) * 0.3
111                            + Math.sin(3 * fundamental1_Hz * 2 * Math.PI
112                                    * samples[channelNumber]) * 0.3
113                            + Math.sin(4 * fundamental1_Hz * 2 * Math.PI
114                                    * samples[channelNumber]) * 0.2;
115
116                    // Increment time for the signal on this channel.
117                    samples[channelNumber] = samples[channelNumber]
118                            + 1.0 / sampleRate;
119
120                    channelNumber = 1; //Right channel.
121
122                    // Generate a harmonic signal.
123                    samplesArray[channelNumber][i] = Math
124                            .sin(fundamental2_Hz * 2 * Math.PI
125                                    * samples[channelNumber])
126                            * 0.4
127                            + Math.sin(2 * fundamental2_Hz * 2 * Math.PI
128                                    * samples[channelNumber]) * 0.3
129                            + Math.sin(3 * fundamental2_Hz * 2 * Math.PI
130                                    * samples[channelNumber]) * 0.25
131                            + Math.sin(4 * fundamental2_Hz * 2 * Math.PI
132                                    * samples[channelNumber]) * 0.2;
133
134                    // Increment time for the signal on this channel.
135                    samples[channelNumber] = samples[channelNumber]
136                            + 1.0 / sampleRate;
137                }
138
139                // Play the processed audio samples.
140                LiveSound.putSamples(_producer, samplesArray);
141
142                // break out of loop after 10 seconds.  0 is the channel number
143                // chosen arbitrarily
144                if (samples[0] > 10.0) {
145                    break;
146                }
147            }
148
149            LiveSound.stopPlayback(_producer);
150        } catch (Throwable throwable) {
151            System.err.println(throwable);
152        }
153    }
154
155    private static Object _producer = new Object();
156}