Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Waveform fails to be generated for big in duration files #12

Open
goxr3plus opened this issue Aug 14, 2018 · 3 comments
Open

Waveform fails to be generated for big in duration files #12

goxr3plus opened this issue Aug 14, 2018 · 3 comments
Assignees
Labels

Comments

@goxr3plus
Copy link

Just found this bug in WaveFormTask.java exactly on line 155 , byte[] buffer = new byte[available]; , tried to run the application but failed to create waveform for audio > 50 minutes .

Further investigation needed . It takes forever to create a buffer array . For example i checked the variable available when it had the value 760163516 which is bigger than Byte.MAX_VALUE it lags forever on creating the byte array , no errors shown too.

Trying to find a solution to pull request .

@goxr3plus
Copy link
Author

goxr3plus commented Aug 16, 2018

Found a temporary solution , though we still need to reduce the final amplitudes array size :

//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();                                                                        
}  

@octaviospain
Copy link
Owner

Thanks for taking the time. I can't help on this until September.
Try to add a test class that exercises your code change, and when it's done feel free to raise a pull request.

@goxr3plus
Copy link
Author

goxr3plus commented Aug 17, 2018

@octaviospain Just for you i made the below awesome solution . No more too much ram used and now it is super duper fast .

I will do a pull request soon :)

/**                                                                                                                                                
 * 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];                                                                                                                             
}    

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants