代码之家  ›  专栏  ›  技术社区  ›  GOXR3PLUS

如何在Java中减小振幅数组的大小?

  •  0
  • GOXR3PLUS  · 技术社区  · 7 年前

    在网上搜索了几个星期,我找到了下面的代码 计算给定的振幅 .wav 用Java编写的文件。现在 问题是它的音效不好,比如

    为了绘制它,我使用JavaFX created this repository (注:由于我几天没有提交,代码可能有所不同)。

    所以:

    /**                                                                                                                             
     * Get Wav Amplitudes                                                                                                           
     *                                                                                                                              
     * @param file                                                                                                                  
     * @return                                                                                                                      
     * @throws UnsupportedAudioFileException                                                                                        
     * @throws IOException                                                                                                          
     */                                                                                                                             
    private int[] getWavAmplitudes(File file) throws UnsupportedAudioFileException , IOException {                                  
        System.out.println("Calculting WAV amplitudes");                                                                            
        int[] amplitudes = null;                                                                                                    
    
        //Get Audio input stream                                                                                                    
        try (AudioInputStream input = AudioSystem.getAudioInputStream(file)) {                                                      
            AudioFormat baseFormat = input.getFormat();                                                                             
    
            Encoding encoding = AudioFormat.Encoding.PCM_UNSIGNED;                                                                  
            float sampleRate = baseFormat.getSampleRate();                                                                          
            int numChannels = baseFormat.getChannels();                                                                             
    
            AudioFormat decodedFormat = new AudioFormat(encoding, sampleRate, 16, numChannels, numChannels * 2, sampleRate, false); 
            int available = input.available();                                                                                      
            amplitudes = new int[available];                                                                                        
    
            //Get the PCM Decoded Audio Input Stream                                                                                
            try (AudioInputStream pcmDecodedInput = AudioSystem.getAudioInputStream(decodedFormat, input)) {                        
                final int BUFFER_SIZE = 4096; //this is actually bytes                                                              
                System.out.println(available);                                                                                      
    
                //Create a buffer                                                                                                   
                byte[] buffer = new byte[BUFFER_SIZE];                                                                              
    
                //Read all the available data on chunks                                                                             
                int counter = 0;                                                                                                    
                while (pcmDecodedInput.readNBytes(buffer, 0, BUFFER_SIZE) > 0)                                                      
                    for (int i = 0; i < buffer.length - 1; i += 2, counter += 2) {                                                  
                        if (counter == available)                                                                                   
                            break;                                                                                                  
                        amplitudes[counter] = ( ( buffer[i + 1] << 8 ) | buffer[i] & 0xff ) << 16;                                  
                        amplitudes[counter] /= 32767;                                                                               
                        amplitudes[counter] *= WAVEFORM_HEIGHT_COEFFICIENT;                                                         
                    }                                                                                                               
            } catch (Exception ex) {                                                                                                
                ex.printStackTrace();                                                                                               
            }                                                                                                                       
        } catch (Exception ex) {                                                                                                    
            ex.printStackTrace();                                                                                                   
        }                                                                                                                           
    
        //System.out.println("Finished Calculting amplitudes");                                                                     
        return amplitudes;                                                                                                          
    }   
    

    然后我处理振幅如下:

    /**                                                                 
     * Process the amplitudes                                           
     *                                                                  
     * @param sourcePcmData                                             
     * @return An array with amplitudes                                 
     */                                                                 
    private float[] processAmplitudes(int[] sourcePcmData) {            
        System.out.println("Processing WAV amplitudes");                
    
        //The width of the resulting waveform panel                     
        int width = waveVisualization.width;                            
        System.out.println("P Width :" + width);                        
        float[] waveData = new float[width];                            
        int samplesPerPixel = sourcePcmData.length / width;             
    
        //Calculate                                                     
        float nValue;                                                   
        for (int w = 0; w < width; w++) {                               
            //if (isCancelled())                                        
            //  break;                                                  
    
            //For performance keep it here                              
            int c = w * samplesPerPixel;                                
            nValue = 0.0f;                                              
    
            //Keep going                                                
            for (int s = 0; s < samplesPerPixel; s++) {                 
                //if (isCancelled())                                    
                //  break;                                              
                nValue += ( Math.abs(sourcePcmData[c + s]) / 65536.0f );
            }                                                           
    
            //Set WaveData                                              
            waveData[w] = nValue / samplesPerPixel;                     
        }                                                               
    
        System.out.println("Finished Processing amplitudes");           
        return waveData;                                                
    }     
    

    结果是:

    enter image description here

    1 回复  |  直到 7 年前
        1
  •  1
  •   GOXR3PLUS    7 年前

    找到了一个很好的解决方案,虽然我不知道最后的数组最大大小应该是什么,经过一些实验。 100.000 似乎是个好数字。

    this github存储库。

    所以方法 变成:

    /**                                                                                                                                                
     * Get Wav Amplitudes                                                                                                                              
     *                                                                                                                                                 
     * @param file                                                                                                                                     
     * @return                                                                                                                                         
     * @throws UnsupportedAudioFileException                                                                                                           
     * @throws IOException                                                                                                                             
     */                                                                                                                                                
    private int[] getWavAmplitudes(File file) throws UnsupportedAudioFileException , IOException {                                                     
    
        //Get Audio input stream                                                                                                                       
        try (AudioInputStream input = AudioSystem.getAudioInputStream(file)) {                                                                         
            AudioFormat baseFormat = input.getFormat();                                                                                                
    
            //Encoding                                                                                                                                 
            Encoding encoding = AudioFormat.Encoding.PCM_UNSIGNED;                                                                                     
            float sampleRate = baseFormat.getSampleRate();                                                                                             
            int numChannels = baseFormat.getChannels();                                                                                                
    
            AudioFormat decodedFormat = new AudioFormat(encoding, sampleRate, 16, numChannels, numChannels * 2, sampleRate, false);                    
            int available = input.available();                                                                                                         
    
            //Get the PCM Decoded Audio Input Stream                                                                                                   
            try (AudioInputStream pcmDecodedInput = AudioSystem.getAudioInputStream(decodedFormat, input)) {                                           
                final int BUFFER_SIZE = 4096; //this is actually bytes                                                                                 
    
                //Create a buffer                                                                                                                      
                byte[] buffer = new byte[BUFFER_SIZE];                                                                                                 
    
                //Now get the average to a smaller array                                                                                               
                int maximumArrayLength = 100000;                                                                                                       
                int[] finalAmplitudes = new int[maximumArrayLength];                                                                                   
                int samplesPerPixel = available / maximumArrayLength;                                                                                  
    
                //Variables to calculate finalAmplitudes array                                                                                         
                int currentSampleCounter = 0;                                                                                                          
                int arrayCellPosition = 0;                                                                                                             
                float currentCellValue = 0.0f;                                                                                                         
    
                //Variables for the loop                                                                                                               
                int arrayCellValue = 0;                                                                                                                
    
                //Read all the available data on chunks                                                                                                
                while (pcmDecodedInput.readNBytes(buffer, 0, BUFFER_SIZE) > 0)                                                                         
                    for (int i = 0; i < buffer.length - 1; i += 2) {                                                                                   
    
                        //Calculate the value                                                                                                          
                        arrayCellValue = (int) ( ( ( ( ( buffer[i + 1] << 8 ) | buffer[i] & 0xff ) << 16 ) / 32767 ) * WAVEFORM_HEIGHT_COEFFICIENT );  
    
                        //Every time you him [currentSampleCounter=samplesPerPixel]                                                                    
                        if (currentSampleCounter != samplesPerPixel) {                                                                                 
                            ++currentSampleCounter;                                                                                                    
                            currentCellValue += Math.abs(arrayCellValue);                                                                              
                        } else {                                                                                                                       
                            //Avoid ArrayIndexOutOfBoundsException                                                                                     
                            if (arrayCellPosition != maximumArrayLength)                                                                               
                                finalAmplitudes[arrayCellPosition] = finalAmplitudes[arrayCellPosition + 1] = (int) currentCellValue / samplesPerPixel;
    
                            //Fix the variables                                                                                                        
                            currentSampleCounter = 0;                                                                                                  
                            currentCellValue = 0;                                                                                                      
                            arrayCellPosition += 2;                                                                                                    
                        }                                                                                                                              
                    }                                                                                                                                  
    
                return finalAmplitudes;                                                                                                                
            } catch (Exception ex) {                                                                                                                   
                ex.printStackTrace();                                                                                                                  
            }                                                                                                                                          
        } catch (Exception ex) {                                                                                                                       
            ex.printStackTrace();                                                                                                                      
    
        }                                                                                                                                              
    
        //You don't want this to reach here...                                                                                                         
        return new int[1];                                                                                                                             
    }  
    

    任何建议和改进都非常欢迎。