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

Cannot pass an inputstream to Libgdx classes without touching the hard disk. #7400

Open
6 tasks done
Daburnell112 opened this issue May 18, 2024 · 6 comments
Open
6 tasks done

Comments

@Daburnell112
Copy link

Daburnell112 commented May 18, 2024

I want to pass raw audio I am generating from an AudioInputStream to a Sound so that I can modify the pitch as I play it.

                       byte[] buffer = new byte[1024];
                       int bytesRead;
                       while ((bytesRead = audioInputStream.read(buffer)) != -1) {
                                  //There is no way to pass data from RAM in any form to any LibGDX function that requires a FileHandle.
                                  Sound sound = audio.newSound(buffer);
                                  //Ideally I'd just do this.
                                  sound.play(volume,1.5f,0f);
                       }

There's only one workaround for this, and it's writing to a temporary file on the hard disk resulting in tons of lag in the audio:

			//Massive overhead on anything but a SSD, probably not thread safe.
                        FileOutputStream stream = new FileOutputStream(new File("./temp_wav.wav"));
			AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, stream);
                        //Once we write to the hard disk only then can we load the file.
                        Sound sound = Gdx.audio.newSound(Gdx.files.internal("./temp_wav.wav"));
                        sound.play(pitch,0.5f,0f);

This leads to a bigger concern, and that is there's no way in general to create LibGDX class files (Anywhere that requires a call to Gdx.files.internal/local/etc) and modifying the data in RAM without first writing to the hard disk temporally, then loading that afterwards.

Ideally I'd have constructors that would allow you to pass InputStream instead of files (per every example in StackOverflow) that allow me to create classes like Sound or Texture that way.

If there's a workaround, let me know.

  • Android
  • iOS
  • HTML/GWT
  • Windows
  • Linux
  • macOS
@Berstanio
Copy link
Contributor

Berstanio commented May 18, 2024

Hi,
have you checked out https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/audio/AudioDevice.java , whether this works for your case?

This leads to a bigger concern, and that is there's no way in general to create LibGDX class files (Anywhere that requires a call to Gdx.files.internal/local/etc) and modifying the data in RAM without first writing to the hard disk temporally, then loading that afterwards.

I never did this/tested this, but I guess you can just implement your own RAMFileHandle and override things like the read methods?

@PokeMMO
Copy link
Contributor

PokeMMO commented May 18, 2024

A RAMFileHandle will work on desktop, but not Android. (I don't know about iOS or GWT either).

@Daburnell112
Copy link
Author

Hi, have you checked out https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/audio/AudioDevice.java , whether this works for your case?

This leads to a bigger concern, and that is there's no way in general to create LibGDX class files (Anywhere that requires a call to Gdx.files.internal/local/etc) and modifying the data in RAM without first writing to the hard disk temporally, then loading that afterwards.

I never did this/tested this, but I guess you can just implement your own RAMFileHandle and override things like the read methods?

That won't work because there's no way to modify the pitch for that.

@JsonMack
Copy link

@Daburnell112 It looks like there is a class called FileHandleStream which is intended for this purpose. It does create a file when constructing the object (I think), but you don't need to write to it. Just store the InputStream in memory and use that.

try (FileHandle handle : new FileHandleByteStream("foo.bar", new ByteArrayInputStream(myBytes)) {
    Sound sound = audio.newSound(handle);
}
public class FileHandleByteStream extends FileHandleStream implements AutoCloseable {

    private final InputStream data;

    public FileHandleByteStream(String path, InputStream data) {
        super(path);
        this.data = data;
    }

    @Override
    public InputStream read() {
        return data;
    }

    @Override
    public void close() throws Exception {
        data.close();
    }
}

@Frosty-J
Copy link
Contributor

That won't work because there's no way to modify the pitch for that.

There kind of is. AudioDevice is quite a low-level API, so it's up to you to interpolate samples as desired.

@Daburnell112
Copy link
Author

Daburnell112 commented Jun 1, 2024

That won't work because there's no way to modify the pitch for that.

There kind of is. AudioDevice is quite a low-level API, so it's up to you to interpolate samples as desired.

The difficulty involved in doing this is substantial.

I wouldn't expect anyone to write a pitch-shifting algorithm for a unique case without a series of spikes.

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

No branches or pull requests

5 participants