Changeset 1007 for trunk


Ignore:
Timestamp:
03/08/16 23:22:09 (8 years ago)
Author:
davidb
Message:

Generalization of audio support to allow playback/mixer to be stereo, plus some edits to comments

Location:
trunk/src/org/apollo
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/apollo/audio/ApolloPlaybackMixer.java

    r375 r1007  
    324324                if (playbackThread == null) {
    325325               
    326                         playbackThread = new PlaybackThread();
     326                        AudioFormat audio_format = SampledAudioManager.getInstance().getDefaultPlaybackFormat();
     327                        if (audio_format.getChannels()==2) {
     328                                playbackThread = new StereoPlaybackThread();
     329                        }
     330                        else {
     331                                playbackThread = new MonoPlaybackThread();
     332                        }
    327333                        playbackThread.start();
    328334                       
     
    451457         *
    452458         */
    453         private class PlaybackThread extends Thread {
    454                
    455                 private SourceDataLine srcDataLine; // never null
    456 
    457                 private boolean isStopping = false;
    458                
    459                 private int bufferFrameLength;
    460                 private boolean isOutputBigEndian;
     459        private abstract class PlaybackThread extends Thread {
     460               
     461                protected SourceDataLine srcDataLine; // never null
     462
     463                protected boolean isStopping = false;
     464               
     465                protected int bufferFrameLength;
     466                protected boolean isOutputBigEndian;
    461467               
    462468                /**
     
    465471                 * @throws LineUnavailableException
    466472                 */
    467                 PlaybackThread() throws LineUnavailableException {
    468                         super("Apollo Playback Mixer Thread");
     473                protected PlaybackThread(String threadName) throws LineUnavailableException {
     474                        super(threadName);
    469475                        super.setPriority(Thread.MAX_PRIORITY);
    470476                       
     
    494500                 *              If failed to acquire the source data line.
    495501                 */
    496                 private void aquireSourceDataLine() throws LineUnavailableException {
     502                protected void aquireSourceDataLine() throws LineUnavailableException {
    497503
    498504                        // Select an audio output format
     
    508514                       
    509515                        // Cache useful data
    510                         bufferFrameLength = srcDataLine.getBufferSize() / 2;
     516                        bufferFrameLength = srcDataLine.getBufferSize() / (2*2); // 2=stereo, 2=16-bit
    511517                        isOutputBigEndian = srcDataLine.getFormat().isBigEndian();
    512518                       
     
    527533               
    528534                /**
    529                  * Note: even if all tracks have been proccessed in the audio pipeline, it will
     535                 * Note: even if all tracks have been processed in the audio pipeline, it will
    530536                 * commence another pass to check for new tracks added to the graph before finishing.
    531537                 *
     
    540546                 * @return the best audio format for playback...
    541547                 */
    542                 private AudioFormat getAudioFormat() {
     548                protected AudioFormat getAudioFormat() {
    543549                        return SampledAudioManager.getInstance().getDefaultPlaybackFormat();
    544550                }
    545551
     552                /**
     553                 * The audio mixing pipeline
     554                 */
     555                public abstract void run();
     556       
     557
     558               
     559        }
     560
     561    private class StereoPlaybackThread extends PlaybackThread {
     562               
     563
     564               
     565                /**
     566                 * Initantly prepares for audio playback: Opens the (stereo) source data line for output
     567                 *
     568                 * @throws LineUnavailableException
     569                 */
     570                StereoPlaybackThread() throws LineUnavailableException {
     571                        super("Apollo Stereo Playback Mixer Thread");
     572                       
     573                }
     574               
     575       
     576                /**
     577                 * The audio mixing pipeline
     578                 */
     579                public void run() {
     580
     581                        // Notify observers that some audio has started playing
     582                        ApolloPlaybackMixer.this.fireSubjectChangedLaterOnSwingThread(
     583                                new SubjectChangedEvent(ApolloSubjectChangedEvent.PLAYBACK_STARTED));
     584                       
     585                        // All tracks to play per pass
     586                        List<TrackSequence> tracksToPlay = new LinkedList<TrackSequence>();
     587                       
     588                        // Keeps track of tracks to remove
     589                        List<TrackSequence> completedTracks = new LinkedList<TrackSequence>();
     590                       
     591                        // The buffer written directly to the source data line
     592                        byte[] sampleBuffer = new byte[2 * 2 * bufferFrameLength]; // 2=stereo, 2=16-bit samples
     593                       
     594                        // The mixed frames, where each element refers to a frame
     595                        int[] mixedFrameBufferL = new int[bufferFrameLength];
     596                        int[] mixedFrameBufferR = new int[bufferFrameLength];
     597                       
     598                        // Helpers declared outside loop for mz efficiency
     599                        int msbL, lsbL;
     600                        int msbR, lsbR;
     601                        int sampleL;
     602                        int sampleR;
     603                        int totalFramesMixed;
     604                        int trackCount; // tracks to play at a given pass
     605                        boolean isMoreQueued; // True if there are more tracks queued.
     606                        int frameIndex;
     607                        int i;
     608                       
     609                        // Begin writing to the source data line
     610                        if (srcDataLine.isOpen())
     611                                srcDataLine.start();
     612                        else return;
     613
     614                        // keep playing as long as line is open (and there is something to play)
     615                        try
     616                        {
     617                                while (srcDataLine.isOpen()) { // The audio mixing pipline
     618
     619                                        // First decide on which tracks to play ... and remove any finished tracks.
     620                                        synchronized(sequenceGraph) {
     621                                               
     622                                                // If there are no more tracks queued for playing, then exit the
     623                                                // playback thread.
     624                                                if (sequenceGraph.isEmpty())
     625                                                        return;
     626               
     627                                                isMoreQueued = false;
     628                                                completedTracks.clear();
     629                                                tracksToPlay.clear();
     630                                               
     631                                                for (TrackSequence ts : sequenceGraph) {
     632                                                       
     633                                                        // Has this track sequence finished?
     634                                                        if (ts.currentFrame > ts.endFrame || ts.stopPending)
     635                                                                completedTracks.add(ts);
     636                                                       
     637                                                        // Is this track playing / is meant to start laying in this pass?
     638                                                        else if (ts.initiationFrame <= (timelineFrame + bufferFrameLength))
     639                                                                tracksToPlay.add(ts);
     640       
     641                                                        // If it is not time to play the track yet, then
     642                                                        // neither will it for all proceeding tracks either
     643                                                        // since they are ordered by their initiation time.
     644                                                        else break;
     645                                                       
     646                                                }
     647                                               
     648                                                // Get rid of tracks that have finished playing. Notify models that they have stopped
     649                                                for (TrackSequence staleTS : completedTracks) {
     650                                                       
     651                                                        sequenceGraph.remove(staleTS);
     652                                                       
     653                                                        staleTS.onStopped((staleTS.currentFrame > staleTS.endFrame)
     654                                                                        ? staleTS.endFrame : staleTS.currentFrame);
     655                                                       
     656                                                        //removeTrackFromGraph(staleTS, staleTS.endFrame);
     657                                                }
     658
     659                                                trackCount = tracksToPlay.size();
     660                                                isMoreQueued = sequenceGraph.size() > trackCount;
     661                                               
     662                                                // If there is nothing queued and there are no tracks to play,
     663                                                // then playback is finished.
     664                                                if (!isMoreQueued && trackCount == 0)
     665                                                        return;
     666                                               
     667                                        } // release lock
     668                                       
     669                                        totalFramesMixed = 0; // this will be set to the maximum amount of frames that were mixed accross all tracks
     670                                       
     671                                        // Clear audio buffer
     672                                        for (i = 0; i < bufferFrameLength; i++) {
     673                                                // TODO: Efficient way of clearing buffer?
     674                                                mixedFrameBufferL[i] = 0;
     675                                                mixedFrameBufferR[i] = 0;
     676                                        }
     677                                       
     678                                        // Perform Mixing :
     679                                        // Convert the sample size to 16-bit always for best precision while
     680                                        // processing audio in the mix pipeline....
     681                                        for (TrackSequence ts : tracksToPlay) {
     682                                               
     683                                                // Notify model that initiated
     684                                                if (!ts.isPlaying()) ts.onInitiated(timelineFrame);
     685
     686                                                // Skip muted / unsoloed tracks - they add nothing to the sample mix
     687                                                if (ts.isMuted || (isSoloEnable && !ts.isSolo)) {
     688                                                       
     689                                                        // Make sure start where initiated, if not already initiated
     690                                                        if (ts.initiationFrame >= timelineFrame && ts.initiationFrame < (timelineFrame + bufferFrameLength)) {
     691                                                               
     692                                                                // Get index in frame buffer where to initiate
     693                                                                frameIndex = (int)(ts.initiationFrame - timelineFrame);
     694                                                               
     695                                                                // Calcuate the length of frames to buffer - adjust silent tracks position
     696                                                                ts.currentFrame += (bufferFrameLength - frameIndex);
     697
     698                                                        } else { // skip full buffer of bytes ... silenced
     699                                                               
     700                                                                ts.currentFrame += bufferFrameLength; // currentFrame can go outside endframe boundry of the track
     701                               
     702                                                        }
     703                                                       
     704                                                        totalFramesMixed = bufferFrameLength;
     705                                                       
     706                                                } else { // Get samples and add to mix
     707       
     708                                                        // If the track is yet to initiate - part way through the buffer, then start adding bytes
     709                                                        // at initiation point
     710                                                        if (ts.initiationFrame >= timelineFrame && ts.initiationFrame < (timelineFrame + bufferFrameLength)) {
     711                                                               
     712                                                                frameIndex = (int)(ts.initiationFrame - timelineFrame);
     713                                                               
     714                                                        } else {
     715                                                               
     716                                                                frameIndex = 0;
     717                                                               
     718                                                        }
     719               
     720                                                        // For each frame
     721                                                        for (;frameIndex < bufferFrameLength && ts.currentFrame <= ts.endFrame; frameIndex++) {
     722                                                               
     723                                                                // Get sample according to byte order
     724                                                                int base_posL = ts.currentFrame * (2*2); // 2=stereo, 2=16-bit
     725                                                                int base_posR = base_posL+2;
     726                                                               
     727                                                                if (ts.isBigEndian) {
     728                                                                       
     729                                                                        // First byte is MSB (high order)
     730                                                                        msbL = (int)ts.playbackAudioBytes[base_posL];
     731                                                                         
     732                                                                         // Second byte is LSB (low order)
     733                                                                        lsbL = (int)ts.playbackAudioBytes[base_posL + 1];
     734                                                                       
     735                                                                        // And again for the right channel
     736                                                                        msbR= (int)ts.playbackAudioBytes[base_posR];
     737                                                                        lsbR = (int)ts.playbackAudioBytes[base_posR + 1];
     738                                                               
     739                                                                 } else {
     740                                                                         
     741                                                                        // First byte is LSB (low order)
     742                                                                        lsbL = (int)ts.playbackAudioBytes[base_posL];
     743                                                                         
     744                                                                        // Second byte is MSB (high order)
     745                                                                        msbL = (int)ts.playbackAudioBytes[base_posL+1];
     746                                                                       
     747                                                                        // And again for the right channel
     748                                                                        lsbR = (int)ts.playbackAudioBytes[base_posR];
     749                                                                        msbR = (int)ts.playbackAudioBytes[base_posR+1];
     750                                                                }
     751                                                               
     752                                                                sampleL = (msbL << 0x8) | (0xFF & lsbL);
     753                                                                sampleR = (msbR << 0x8) | (0xFF & lsbR);
     754                                                               
     755                                                                // Apply track volume
     756                                                                sampleL = (int)(sampleL * ts.volume);
     757                                                                sampleR = (int)(sampleR * ts.volume);
     758                                                               
     759                                                                // Add to current mix
     760                                                                mixedFrameBufferL[frameIndex] += sampleL;
     761                                                                mixedFrameBufferR[frameIndex] += sampleR;
     762                                                               
     763                                                                // Get next sample
     764                                                                ts.currentFrame++;
     765                                                        }
     766                                                       
     767                                                       
     768                                                        // Keep track of total frames mixed in buffer
     769                                                        if (frameIndex > totalFramesMixed)
     770                                                                totalFramesMixed = frameIndex;
     771                                                }
     772               
     773                                        } // Mix in next track
     774       
     775                                        // totalFramesMixed is the amount of frames to play.
     776                                        // If it is zero then it means that there are tracks yet to be initiated, and nothing currently playing
     777                                        assert (totalFramesMixed <= bufferFrameLength);
     778                                        assert (totalFramesMixed > 0 ||
     779                                                        (totalFramesMixed == 0 && trackCount == 0 && isMoreQueued));
     780                                       
     781                                        // Post mix with master settings
     782                                        if (isMasterMuteOn) { // Silence sample buffer if master mute is on
     783       
     784                                                for (i = 0; i < sampleBuffer.length; i++) {
     785                                                        sampleBuffer[i] = 0;
     786                                                }
     787                                               
     788                                                // Let the muted bytes play
     789                                                totalFramesMixed = bufferFrameLength;
     790                                               
     791                                        } else { // otherwise apply master volume
     792                                               
     793                                                for (i = 0; i < totalFramesMixed; i++) {
     794               
     795                                                        // Average tracks
     796                                                        //mixedFrameBuffer[i] /= trackCount; // depreciated
     797                                                       
     798                                                        // Apply master volume
     799                                                        mixedFrameBufferL[i] = (int)(mixedFrameBufferL[i] * masterVolume);
     800                                                        mixedFrameBufferR[i] = (int)(mixedFrameBufferR[i] * masterVolume);
     801                                                       
     802                                                        // Clip
     803                                                        if (mixedFrameBufferL[i] > Short.MAX_VALUE) mixedFrameBufferL[i] = Short.MAX_VALUE;
     804                                                        else if (mixedFrameBufferL[i] < Short.MIN_VALUE) mixedFrameBufferL[i] = Short.MIN_VALUE;
     805                                                       
     806                                                        if (mixedFrameBufferR[i] > Short.MAX_VALUE) mixedFrameBufferR[i] = Short.MAX_VALUE;
     807                                                        else if (mixedFrameBufferR[i] < Short.MIN_VALUE) mixedFrameBufferR[i] = Short.MIN_VALUE;
     808                                                       
     809                                                        // Convert to output format
     810                                                        lsbL = (mixedFrameBufferL[i] & 0xFF);
     811                                                        msbL = ((mixedFrameBufferL[i] >> 8) & 0xFF);
     812                                                        lsbR = (mixedFrameBufferR[i] & 0xFF);
     813                                                        msbR = ((mixedFrameBufferR[i] >> 8) & 0xFF);
     814                                                       
     815                                                        int base_posL = i * (2 * 2); // 2=stereo, 2=16-bits
     816                                                        int base_posR = base_posL + 2;
     817                                                        if (isOutputBigEndian) {
     818                                                                sampleBuffer[base_posL]   = (byte)msbL;
     819                                                                sampleBuffer[base_posL+1] = (byte)lsbL;
     820                                                                sampleBuffer[base_posR]   = (byte)msbR;
     821                                                                sampleBuffer[base_posR+1] = (byte)lsbR;
     822                                                        } else {
     823                                                                sampleBuffer[base_posL]   = (byte)lsbL;
     824                                                                sampleBuffer[base_posL+1] = (byte)msbL;
     825                                                                sampleBuffer[base_posR]   = (byte)lsbR;
     826                                                                sampleBuffer[base_posR+1] = (byte)msbR;
     827                                                        }
     828
     829                                                }
     830
     831                                        }
     832                                       
     833                                        // Generate silence only if there are more tracks to be played.
     834                                        // Note that this could be false, but a track might have been queued after
     835                                        // setting the isMoreQueued flag. In such cases... silence is not wanted anyway!
     836                                        if (isMoreQueued) {
     837                                                for (i = totalFramesMixed; i < bufferFrameLength; i++) { // will skip if no need to generate silence
     838                                                        int base_posL = i * (2 * 2); // 2=stereo, 2=16-bits
     839                                                        int base_posR = base_posL + 2;
     840                                                       
     841                                                        sampleBuffer[base_posL]   = 0;
     842                                                        sampleBuffer[base_posL+1] = 0;
     843                                                        sampleBuffer[base_posR]   = 0;
     844                                                        sampleBuffer[base_posR+1] = 0;
     845                                                }
     846                                                // Ensure that full buffer is played ... including the silence
     847                                                totalFramesMixed = bufferFrameLength;
     848                                        }
     849       
     850                                        // Write processed bytes to line out stream and update the timeline frame
     851                                        srcDataLine.write(
     852                                                        sampleBuffer,
     853                                                        0,
     854                                                        totalFramesMixed * (2 * 2)); // 2=stereo, 2=16-bits
     855                                       
     856                                        // Update timeline counter for sequencing management
     857                                        timelineFrame += totalFramesMixed;
     858                                       
     859                                        // The timelineFrame should always be larger or equal to the live frame position
     860                                        assert(timelineFrame >= srcDataLine.getLongFramePosition());
     861                                       
     862                                } // Next pass
     863                       
     864                        } finally {
     865                               
     866                                isStopping = true;
     867                               
     868                                // Ensure line freed
     869                                if (srcDataLine.isOpen()) {
     870                                        srcDataLine.drain(); // avoids chopping off last buffered chunk
     871                                        srcDataLine.close();
     872                                }
     873                               
     874                                // Clear sequence graph.
     875                                synchronized(sequenceGraph) {
     876                                       
     877                                        for (TrackSequence track : sequenceGraph) {
     878                                               
     879                                                track.onStopped((track.currentFrame > track.endFrame)
     880                                                                ? track.endFrame : track.currentFrame);
     881                                        }
     882                                       
     883                                        sequenceGraph.clear();
     884                                       
     885                                }
     886
     887                                // Notify observers that playback has finished.
     888                                ApolloPlaybackMixer.this.fireSubjectChangedLaterOnSwingThread(
     889                                                new SubjectChangedEvent(ApolloSubjectChangedEvent.PLAYBACK_STOPPED));
     890                               
     891                        }
     892                       
     893                }
     894        }
     895   
     896    private class MonoPlaybackThread extends PlaybackThread {
     897               
     898
     899               
     900                /**
     901                 * Initantly prepares for audio playback: Opens the (stereo) source data line for output
     902                 *
     903                 * @throws LineUnavailableException
     904                 */
     905                MonoPlaybackThread() throws LineUnavailableException {
     906                        super("Apollo Mono Playback Mixer Thread");
     907                       
     908                }
     909               
    546910                /**
    547911                 * The audio mixing pipeline
     
    6371001                                       
    6381002                                        // Clear audio buffer
    639                                         for (i = 0; i < bufferFrameLength; i++) // TODO: Effecient way of clearing buffer?
     1003                                        for (i = 0; i < bufferFrameLength; i++) // TODO: Efficient way of clearing buffer?
    6401004                                                mixedFrameBuffer[i] = 0;
    6411005                                       
     
    7461110                                                        //mixedFrameBuffer[i] /= trackCount; // depreciated
    7471111                                                       
    748                                                         // Apply mastar volume
     1112                                                        // Apply master volume
    7491113                                                        mixedFrameBuffer[i] = (int)(mixedFrameBuffer[i] * masterVolume);
    7501114                                                       
     
    7811145                                        }
    7821146       
    783                                         // Write proccessed bytes to line out stream and update the timeline frame
     1147                                        // Write processed bytes to line out stream and update the timeline frame
    7841148                                        srcDataLine.write(
    7851149                                                        sampleBuffer,
     
    8261190                }
    8271191               
    828 
    829                
    830         }
     1192    }
    8311193
    8321194       
  • trunk/src/org/apollo/audio/SampledAudioManager.java

    r355 r1007  
    1414import org.apollo.mvc.SubjectChangedEvent;
    1515import org.apollo.util.ApolloSystemLog;
     16
    1617
    1718/**
     
    2728       
    2829        /** All internal formats have the same sample rate. */
    29         public static final float PLAYBACK_SAMPLE_RATE = 44100.0f; // Audacitys default
    30        
    31         //public static final float PLAYBACK_SAMPLE_RATE = 22050.0f; // Meldexes internal rate .. todo: fix conversions to use better rate
    32 
    33         // Used for describing the ideal default format for recorded audio and converting un-supported
     30        // The following is based on Audacity's defaults for playback
     31        public static final float PLAYBACK_SAMPLE_RATE      = 44100.0f;
     32        public static final int   PLAYBACK_BITS_PER_SAMPLE  = 16;     
     33        public static final int   PLAYBACK_NUM_CHANNELS     = 2; // stereo
     34       
     35        //public static final float PLAYBACK_SAMPLE_RATE = 22050.0f; // Meldexe's internal rate .. todo: fix conversions to use better rate
     36
     37        // Used for describing the ideal default format for recorded audio and converting unsupported
    3438        // imported audio to... The actual formats may differ depending on the data lines used
    3539       
    36         // note: Must be PCM, Mono, 16 bit.
     40        // note: Must be PCM, with values as defined for PLAYBACK_... above
    3741        private static final AudioFormat DESIRED_FORMAT = new AudioFormat( // Linear PCM Encoding
    38                         PLAYBACK_SAMPLE_RATE, // Always conform to PLAYBACK_SAMPLE_RATE
    39                         16, // bits per sample. Must be 16. Audacitys default
    40                         1, // Always use mono. Audacitys default
     42                        PLAYBACK_SAMPLE_RATE, // Always conform to PLAYBACK_SAMPLE_RATE etc
     43                        PLAYBACK_BITS_PER_SAMPLE,
     44                        PLAYBACK_NUM_CHANNELS,
    4145                        false, // ALWAYS USED SIGNED FOR BEST PERFORMACE - JAVA DOES NOT HAVE UNSIGNED TYPES
    4246                        true // Byte order
     
    231235                        // Not cadidate if not in appollos format.
    232236                        if (!candiate.getEncoding().toString().startsWith("PCM")
    233                                         || candiate.getChannels() != 1
    234                                         || candiate.getSampleSizeInBits() != 16
     237                                        || candiate.getChannels() != PLAYBACK_NUM_CHANNELS
     238                                        || candiate.getSampleSizeInBits() != PLAYBACK_BITS_PER_SAMPLE
    235239                                        || (candiate.getSampleRate() != AudioSystem.NOT_SPECIFIED &&
    236240                                                        candiate.getSampleRate() != PLAYBACK_SAMPLE_RATE))
     
    285289        /**
    286290         * Determines if an audio format requires conversion in order to be used
    287          * in Apollos.
    288          *
    289          * Audio formats must be in PCM, mono, 16-bit sample-size,
     291         * in Apollo's.
     292         *
     293         * Audio formats must be in PCM, SampledAudioManager#PLAYBACK_NUM_CHANNELS,
     294         * SampledAudioManager#PLAYBACK_BITS_PER_SAMPLE sample-size,
    290295         * SampledAudioManager#PLAYBACK_SAMPLE_RATE sample-rate and be supported
    291296         * by the output mixer.
     
    304309                if (format == null) throw new NullPointerException("format");
    305310               
    306                 if(!format.getEncoding().toString().startsWith("PCM") || format.getChannels() != 1
    307                                 || format.getSampleSizeInBits() != 16
     311                if(!format.getEncoding().toString().startsWith("PCM") || format.getChannels() != PLAYBACK_NUM_CHANNELS
     312                                || format.getSampleSizeInBits() != PLAYBACK_BITS_PER_SAMPLE
    308313                                || (format.getSampleRate() != AudioSystem.NOT_SPECIFIED &&
    309314                                                format.getSampleRate() != PLAYBACK_SAMPLE_RATE)) {
     
    313318                // Check that the format is supported by the output mixer
    314319                for (AudioFormat supported : supportedPlaybackFormats) {
    315                         if (supported.getChannels() != 1) continue;
     320                        if (supported.getChannels() != PLAYBACK_NUM_CHANNELS) continue;
    316321                        if (
    317322                                        format.getEncoding() == supported.getEncoding()
  • trunk/src/org/apollo/gui/DualPeakTroughWaveFormRenderer.java

    r353 r1007  
    1414       
    1515        private int sampleSize;
     16        private int numChannels;
    1617        private boolean isBigEndian;
    1718        private boolean isSigned;
     
    3637
    3738                sampleSize = audioFormat.getSampleSizeInBits();
     39                numChannels = audioFormat.getChannels();
    3840                isSigned = audioFormat.getEncoding().toString().startsWith("PCM_SIGN");
    3941                isBigEndian = audioFormat.isBigEndian();
     
    8183                if (sampleSize == 16) {
    8284                                         
     85                        int shift_multiplier = numChannels; // <<1=16-bit-mono, <<2=16-bit-stereo
    8386                        for (int i = 0; i < aggregationCount; i++) {
    8487                               
    8588                                int max = 0, min = 0, sample; // could use short, but int avoids casting everywhere
    8689                               
    87                                 int startFrameIndex = (startFrame + (i * aggregationSize)) << 1;
    88                                 int endFrameIndex = startFrameIndex + (aggregationSize << 1);
     90                                int startFrameIndex = (startFrame + (i * aggregationSize)) << shift_multiplier;
     91                                int endFrameIndex = startFrameIndex + (aggregationSize << shift_multiplier);
    8992                               
    9093                                for (int k = startFrameIndex; k < endFrameIndex; k+=2) {
    9194                       
     95                                        // k+=2 works for both mono and stereo
     96                                        // in the case of stereo k+=2 alternates between L and R values.
     97                                        // net effect is that it still finds the min and max values across
     98                                        // all samples: startFrameIndex .. endFrameIndex
     99                                         
    92100                                        int lsb, msb;
    93101                                                                 
     
    128136                } else if (sampleSize == 8) {
    129137                       
     138                        int shift_multiplier = numChannels-1; // <<0=8-bit-mono, <<1=8-bit-stereo
     139                       
     140                        // 'i' loop below works for either mono or stereo without any adjustment
     141                        // for same reason above given for 'k' loop
     142                       
    130143                        if (isSigned) {
    131144                 
     145                               
    132146                                // Find the peak within the block of aggregated frames
    133147                                for (int i = 0; i < amplitudes.length; i++) {
     
    135149                                        byte max = 0, absmax = -1, sample, abssample;
    136150
    137                                         int startFrameIndex = startFrame + (i * aggregationSize);
    138                                         int endFrameIndex = startFrameIndex + aggregationSize;
     151                                        int startFrameIndex = (startFrame + (i * aggregationSize)) << shift_multiplier;
     152                                        int endFrameIndex = startFrameIndex + (aggregationSize << shift_multiplier);
    139153                                       
    140154                                        for (int k = startFrameIndex; k < endFrameIndex; k++) {
     
    160174                                        int max = 0, absmax = -1, sample, abssample; // could use short, but int avoid casting everywhere
    161175
    162                                         int startFrameIndex = startFrame + (i * aggregationSize);
    163                                         int endFrameIndex = startFrameIndex + aggregationSize;
     176                                        int startFrameIndex = (startFrame + (i * aggregationSize)) << shift_multiplier;
     177                                        int endFrameIndex = startFrameIndex + (aggregationSize<<shift_multiplier);
    164178                                       
    165179                                        for (int k = startFrameIndex; k < endFrameIndex; k++) {
  • trunk/src/org/apollo/gui/SampledTrackGraphView.java

    r355 r1007  
    9292        public SampledTrackGraphView() {
    9393               
    94                 // Keep backings consistant with component resize
     94                // Keep backings consistent with component resize
    9595                this.addComponentListener(new ComponentListener() {
    9696                        public void componentHidden(ComponentEvent e) {
  • trunk/src/org/apollo/io/AudioIO.java

    r315 r1007  
    2121import org.apollo.mvc.SubjectChangedEvent;
    2222import org.apollo.util.AudioMath;
     23
    2324
    2425/**
     
    4445         *
    4546         * @throws IOException
    46          *              If failed to create file for saving, or an error occured while writing audio bytes.
     47         *              If failed to create file for saving, or an error occurred while writing audio bytes.
    4748         *
    4849         * @throws UnsupportedAudioFileException
     
    505506                                assert (SampledAudioManager.getInstance().isFormatSupportedForPlayback(sampleFormat));
    506507       
    507                                 // Initialize the ByteBuffer - and size if possible (not possible for vairable frame size encoding)
     508                                // Initialize the ByteBuffer - and size if possible (not possible for variable frame size encoding)
    508509                                ByteArrayOutputStream loadedBytes = (fformat.getFrameLength() != AudioSystem.NOT_SPECIFIED) ?
    509510                                                new ByteArrayOutputStream(fformat.getFrameLength() * sampleFormat.getFrameSize()) :
     
    511512
    512513                                byte[] buffer = new byte[sampleFormat.getFrameSize() * (int)sampleFormat.getFrameRate()];
     514                                 
    513515                                int bytesRead = 0;
    514516                                int totalBytesRead = 0;
     
    568570         */
    569571        public static void main(String[] args) {
    570                 if (args.length == 1) {
    571                        
    572                         System.out.println("Testing with " + args[0]);
     572               
     573                String args_zero = null;
     574               
     575                if (args.length==0) {
     576                        // Hardwire to whatever is a meaningful example for you!
     577                        args_zero = "C:\\Temp\\GoodTime_Preview.mp3";
     578                }
     579                else if (args.length==1) {
     580                        args_zero = args[0];
     581                       
     582                }
     583       
     584                System.out.println("Testing with " + args_zero);
    573585                       
    574586                        try {
    575                                 LoadedAudioData loaded = loadAudioFile(new File(args[0]), null);
     587                                LoadedAudioData loaded = loadAudioFile(new File(args_zero), null);
     588                               
    576589                                if (loaded != null && loaded.getAudioBytes() != null) {
    577590                                       
     
    580593                                        if (loaded.wasConverted()) {
    581594                                                savePCMAudioToWaveFile(
    582                                                         args[0] + "_pre-converted.wav",
     595                                                        args_zero + "_pre-converted.wav",
    583596                                                        loaded.getAudioBytes(),
    584597                                                        loaded.getAudioFormat());
     
    603616                                               
    604617                                                savePCMAudioToWaveFile(
    605                                                                 args[0] + "_converted.wav",
     618                                                                args_zero + "_converted.wav",
    606619                                                                stdData,
    607620                                                                lowQualFormat);
     
    625638                        return;
    626639                       
    627                 }
    628                
    629                 System.err.println("Must supply 1 argument: the file path to convert");
     640               
     641                //System.err.println("Must supply 1 argument: the file path to convert");
    630642               
    631643               
  • trunk/src/org/apollo/widgets/SampledTrack.java

    r375 r1007  
    8888        private SampledTrackModel trackModel = null;
    8989       
    90         /** Used for the loading phase. Can change serveal times of a lifetime. for example after import and save it becomes local */
     90        /** Used for the loading phase. Can change several times of a lifetime. for example after import and save it becomes local */
    9191        private String loadFilenameArgument = null; // preproceeds with ARG_IMPORT_TAG if importing.
    9292       
    93         private String localFileName; // Immutable - assigned on constuction
     93        private String localFileName; // Immutable - assigned on construction
    9494       
    9595        /** Used for dumping audio to a temp file when deleted - to free memory.
     
    152152                trackModel = new SampledTrackModel(audioBytes, format, localFileName);
    153153               
    154                 // Ensure that the model is marked as modiefied so that it will save
     154                // Ensure that the model is marked as modified so that it will save
    155155                trackModel.setAudioModifiedFlag(true);
    156156               
Note: See TracChangeset for help on using the changeset viewer.