How to generate audio in java - java

This question has to do with a game console I'm working on, and right now I am trying to write a Java program to simulate the console's DSP. That way, I know exactly what to do when I port it to actual hardware. But I am having trouble finding the right sound library. What I need is basically this: I have my own sound format, and I feed it into the DSP. It then decodes the data, processes post decode effects (echo, amplify, etc.), and splits the results into two sound waves for stereo output. I have everything planned out except a way to get my sound waves to my computer's sound card. So basically a more advanced version of a sine wave generator. And a little code sample to get me started would help. If I need to clarify anything, than let me know.
EDIT: Okay, so just to be clear the sound wave data will be stored in chunks in a byte array. So I need a way of playing sounds from there. And I don't want to dump the audio to a file and then play the file, that would take too long.

Here is one way to generate a sound using java.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.sound.midi.Instrument;
import javax.sound.midi.MidiChannel;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Synthesizer;
import javax.swing.*;
public class SimpleSound extends JFrame{
Synthesizer syn;
MidiChannel[] midChannel;
Instrument[] instrument;
public SimpleSound() {
this.setLayout(new BorderLayout());
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
JButton button1 = new JButton("Try");
this.add(panel);
panel.add(button1);
this.pack();
try {
syn = MidiSystem.getSynthesizer();
syn.open();
midChannel = syn.getChannels();
instrument = syn.getDefaultSoundbank().getInstruments();
syn.loadInstrument(instrument[90]);
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
makeASound();
}
});
} catch (MidiUnavailableException ex) {
ex.printStackTrace();
}
}
void makeASound() {
this.midChannel[5].noteOn(55,550);
// this.midChannel[5].noteOn(70,700);
// this.midChannel[5].noteOn(30,400);
}
public static void main(String[] args) {
new SimpleSound().setVisible(true);
}
}
You can experiment on the values in the code this.midChannel[5].noteOn(55,550);
You can find more explanations here: http://patater.com/gbaguy/javamidi.htm and here: https://docs.oracle.com/javase/tutorial/sound/MIDI-synth.html
Update:
I found another source from here http://www.automatic-pilot.com/midifile.html. It is a simple program demonstrating the creation of MIDI sound and then save it to a file. I made a modification to the last part so that the sound will be written to a byte array instead.
// write to byte array
ByteArrayOutputStream baos = new ByteArrayOutputStream();
MidiSystem.write(s,1,baos);
byte[] bytes = baos.toByteArray();
But I just think that the byte array contents may not have the same format as you what you already have in mind. May I know what is the format of the sound data that is usable to you?

This page pretty much covers all of what I needed. http://www.developer.com/java/other/article.php/2226701/Java-Sound-Creating-Playing-and-Saving-Synthetic-Sounds.htm

Related

Controlling volume of different sound files independent from each other using sliders

I've been working on this project with a peer for comp sci class, and I can't figure out how to make SFX and music have their own independent volume controls. Both the music and the SFX both play just fine when they need to (hovering/clicking on buttons, menu music, etc), and I made sliders for both of them (music volume and SFX volume), but for some reason only music can be controlled. I have sat here for hours trying to figure out why it doesn't work. The FloatControl gain does update with the slider (I printed out it's value and it was working just fine, just not updating the actual volume of the sound effects). I also got rid of everything to do with the music by commenting out everything regarding it's slider controls, audio input stream, gain control, etc; it was as if SFX was the only audio related thing in the program, but it still didn't work. I don't understand why since the code is identical to the music's code (just that "music" is now "sound").
The below code is not meant to be functional on it's own since the actual code is 605 lines so far and that's too long to post on here. It does contain the core components, so if you want to set it up to work you have to make the JFrame and all the buttons, or have me post the full code and sound files.
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.sound.sampled.*;
import java.awt.event.*;
import javax.swing.border.Border;
import javax.swing.BorderFactory;
import java.io.*;
import java.io.File.*;
import java.io.IOException;
public class AudioTesting {
// Declare Global Objects
static final String[] SFXName = {"menuHover", "buttonEnter", "buttonLeave", "gameStart"};
static final String[] TrackName = {"Bossfight_Incomplete"};
static final String userName = System.getProperty("user.name");
static Clip sound;
static Clip music;
static JSlider musicVolumeSlider;
static JSlider soundVolumeSlider;
public static void main(String []args){
GameSetting();
}
public static void GameSetting(){
musicVolumeSlider = new JSlider(-45,6,6);
soundVolumeSlider = new JSlider(-45,6,6);
musicVolumeSlider.setMajorTickSpacing(5);
musicVolumeSlider.setMinorTickSpacing(1);
musicVolumeSlider.setPaintTicks(true);
//musicVolumeSlider.setPreferredSize(new Dimension(SLIDER_SIZE_X,SLIDER_SIZE_Y));
// musicVolumeSlider.setBackground(menuColor);
musicVolumeSlider.addChangeListener(new SliderListener());
soundVolumeSlider.setMajorTickSpacing(5);
soundVolumeSlider.setMinorTickSpacing(1);
soundVolumeSlider.setPaintTicks(true);
// soundVolumeSlider.setPreferredSize(new Dimension(SLIDER_SIZE_X,SLIDER_SIZE_Y));
// soundVolumeSlider.setBackground(menuColor);
soundVolumeSlider.addChangeListener(new SliderListener());
}
//manages the loading and playing of sfx
public static void SFXManager(int sfx){
try{
sound = AudioSystem.getClip();
File sfxFile = new File("C:\\Users\\" + userName + "\\Documents\\" + SFXName[sfx] + ".wav");
sound.open(AudioSystem.getAudioInputStream(sfxFile));
}catch (Exception ex){}
sound.flush();
sound.start();
}
// manages the loading and playing of music tracks
public static void MusicManager(int track){
try{
music = AudioSystem.getClip();
File musicFile = new File("C:\\Users\\" + userName + "\\Documents\\" + TrackName[track] + ".wav");
music.open(AudioSystem.getAudioInputStream(musicFile));
}catch (Exception ex){}
music.start();
music.loop(Clip.LOOP_CONTINUOUSLY);
}
static class SliderListener implements ChangeListener {
public void stateChanged(ChangeEvent e) throws IllegalArgumentException {
float currentMusicVolume = 0;
float currentSoundVolume = 0;
FloatControl musicGainControl = (FloatControl) music.getControl(FloatControl.Type.MASTER_GAIN);
FloatControl soundGainControl = (FloatControl) sound.getControl(FloatControl.Type.MASTER_GAIN);
//-------------------------------------------------------------PROBLEM AREA v v v
//For changing the volume of the music (this works just fine)
if (e.getSource() == musicVolumeSlider){
currentMusicVolume = musicVolumeSlider.getValue();
//if the slider is all the way at it's lowest, set the volume to -80 (i.e. mute)
if (currentMusicVolume == -45){
currentMusicVolume = -80;
}
musicGainControl.setValue(currentMusicVolume); // Reduce volume by slider value
}
//for changing the volume of the sfx
if (e.getSource() == soundVolumeSlider){
currentSoundVolume = soundVolumeSlider.getValue();
//if the slider is all the way at it's lowest, set the volume to -80 (i.e. mute)
if (currentSoundVolume == -45){
currentSoundVolume = -80;
}
soundGainControl.setValue(currentSoundVolume); // Reduce volume by slider value
}
}
}
//-------------------------------------------------------------PROBLEM AREA ^ ^ ^
// I didn't implement it in here, but here is where all the mouse and event listeners go for the different buttons
// If a button is hovered over or pressed, it plays a sound from the index that corresponds with that sound
// I.e. if you hover over a button, call SFXManager(0); which plays the first sound in the array (buttonHover.wav) etc.
}
I've found these float controls to be kind of hit-or-miss, in part because they depend on the local PC and its OS. It's often the case that only the master gain works, if you want to change volumes in real time. The master gain changes will affect ALL the playing sounds.
You could follow the suggestion from the last paragraphs of the Oracle sound tutorial on audio controls and write your own volume controls. To do so requires intercepting the audio input stream, compiling the bytes into PCM, multiplying the PCM by a volume factor, converting the PCM back to bytes, and finally, shipping the bytes out via a SourceDataLine.
This is basically the plan I followed when I wrote AudioCue. You are welcome to use that code base as an example for rolling your own, or to import and directly make use of the files within your project. I tried to follow the Clip API as closely as I could, while adding real time volume controls for each playing audio instance. One limitation is that it only works with wav files. But if you can work with that, feel free to use the library. I'm happy to answer any questions if you have any trouble setting it up.
I'm currently learning how to make the program available as a Maven resource. I'm not clear on how the Gradle instructions work--another contributor did that part. It is pretty easy to just copy the five files into your project and use them with just a little tinkering to the import/package lines.

How to emulate temporary text editor on a throwaway file

I have a basic text based Java app. I want the user to be able to enter sensitive info (password) in a text editing session that only exists for that purpose.
A bit like with git you get a temporary session/file in vi (or another set editor) to edit comment and save/quit - then the git process resumes and consumes that file. The file is (probably) deleted or at least forgotten about.
Do not need any advanced editor capabilities, just basic typing, backspace etc.
I want the user to be able to see what they're typing BUT once they have typed a password, it must be erased from screen. So plain STDIN won't work as the input remains on the screen.
How can I do it in Java or for that matter in another language?
I have looked at Scanner (basically STDIN) and Console.readPassword (user cannot see what they type).
Perhaps a solution that involves STDIN and immediate erasure of the typed line could be acceptable. But emulating git/vi interplay is more attractive because it's arguably a bit more standard.
EDIT: I have implemented something close - create temp file and run notepad.exe on that, let user save and close notepad, read from temp file, delete it. Simple but it relies on an external tool, needs to be adjusted to run on linux as well.. I would like something more seamless where the behaviour is emulated within the java app itself
Swing is pretty consistently available, here is an example of a method that opens a window, waits until the window is closed, and returns the text.
import javax.swing.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.awt.EventQueue;
import java.awt.event.*;
public class EditMe{
LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<String>(1);
public void showEditor(){
JFrame frame = new JFrame("edit text");
JEditorPane pane = new JEditorPane("txt", "");
frame.add(pane);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.addWindowListener( new WindowAdapter(){
#Override
public void windowClosed(WindowEvent evt){
try{
queue.put(pane.getText());
} catch(InterruptedException e){
//not really possible, but just incase.
throw new RuntimeException(e);
}
}
} );
frame.setSize( 640, 480 );
frame.setVisible(true);
}
public static String getText() throws InterruptedException{
EditMe me = new EditMe();
EventQueue.invokeLater( ()-> me.showEditor() );
return me.queue.take();
}
public static void main(String[] args) throws Exception{
System.out.println("waiting for response");
String s = getText();
System.out.println("response received: \n" + s);
}
}
This would be about equivalent to a notepad solution, but it uses swing that comes with standard jdk's. (There are headless jdk's that don't include swing.)

How to read FNC1 characters in Java JTextArea

I have a hand held scanner that can read GS1-DataMatrix codes(like the ones in the supermarket). I can scan codes in Notepad++ and I can see FNC1 characters are transmited(the GS before 2210, 1D in HEX - first image)
Now I'm trying to read the same GS1 code from Java but isn't working, the FNC1 is not seen by Java.
In Java I only see "01095011010209171719050810ABCD12342110".
I transformed the string to HEX but the result is the same, FNC1 is not in HEX either(second image).
This is the test code:
package gs1.datamatrix;
import java.awt.Font;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
public class GS1DataMatrix {
public static void main(String[] args) {
JFrame f=new JFrame();//creating instance of JFrame
Font font = new Font("Courier New", Font.PLAIN, 16);
JTextArea jtf2 = new JTextArea(); // used to hold the HEX data
jtf2.setBounds(10,250,900, 200);
jtf2.setFont( font.deriveFont( 24.0f) );
jtf2.setLineWrap(true);
f.add(jtf2);//adding button in JFrame
JTextArea jtf1 = new JTextArea(); // scan area for the DataMatrix scanner
jtf1.setBounds(10,10,900, 200);
jtf1.setFont( font.deriveFont( 24.0f) );
jtf1.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) { update(e); }
#Override
public void removeUpdate(DocumentEvent e) { update(e); }
#Override
public void changedUpdate(DocumentEvent e) { update(e); }
public void update(DocumentEvent e) {
try {
Document doc = (Document)e.getDocument();
String hex = String.format("%040x", new BigInteger(1, doc.getText(0, doc.getLength()).getBytes("UTF8"))); // transform to HEX
jtf2.setText(java.util.Arrays.toString(hex.split("(?<=\\G..)"))); // split hex data by 2 characters
jtf1.selectAll();
} catch (Exception ex) {
Logger.getLogger(GS1DataMatrix.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
f.add(jtf1);//adding button in JFrame
f.setSize(1000,500);
f.setLayout(null);
f.setVisible(true);
}
}
First image: this is how Notepad++ reads FNC1(GS special character on black background):
Second image: this is Java result:
Third image: Notepad++ hex dump showing FNC1 as 1D in HEX at every scan:
Later edit
I think there has been a confusion caused by my original post: I don't parse images, the scanner has build in hardware that does this for me and I only receive a text and some special characters(FNC1's).
Some guesses after reading around a bit:
FNC1 does not have a standard representation.
This stackoverflow answer suggests that there is no way to directly encode FNC1 in the default Latin-1 encoding used for transmission.
As a workaround, most readers seem to default to the ASCII control character "Group Separator" (GS, 29, 0x1d).
You are using a swing control to display and work with the data.
Swing is primarily intended for displaying purposes, not for correct data handling purposes.
I assume what happens is that swing strips the non-printable GS character when it's set within the content of the JTextArea
Considering that you're not terribly explicit about how exactly your scanner transfers the data, but you mention "It's more like a keyboard", I assume the scanner transfers the data by pretending to be a keyboard.
You'd be selecting the input, pressing a button on the scanner and it would send data as keypresses.
Now if that is the case, you won't be able to use Swing's DocumentListener/Document to solve this.
The following Stack Overflow question basically refers to the same problem that you have (with the difference that they're using a qrcode instead of a barcode): ASCII Non printable characters in textcomponent
Now the question I linked suggests that you can use a KeyBinding or a KeyListener to fix this. Note that this will in some way break the hexadecimal representation, if you want to print the non-printable character.
UTF-8 does have a special codepoint for ASCII non-printable character representations.
The "Symbol for Group Separator" is located at \u241d. An option to handle this would then be:
jtf1.getInputMap().put(KeyStroke.getKeyStroke(29), "handleGS");
jtf1.getActionMap().put("handleGS", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
jtf1.setText(jtf1.getText() + "\u241d");
}
}
That way the hexadecimal representation should become:
.. , 33, 34, e2, 90, 9d, 32, 31, 31, 30]
Note that because we remapped the GS to Unicode's "SYMBOL_FOR_GS", we get e2, 90, 9d instead of 1d.

Adding entire GUI to JFrame after the fact

Today I have another project that involves the program I have written for work and been working on for well over 6 months. There is a lot of code and classes so I'm going to try to explain the best that I can so you can (hopefully) help me.
Currently my program works by reading a file and allowing a user to make some modifications to that file, then a new file is written. This entire process involves a GUI that is better explained as a series of JOptionPanes, some with imbedded panels.
Here is my goal: Each file uploaded comes with a given number of "batches". My program loops through once for each batch. During a loop each of the relevant JOptionPane GUI's is displayed. When all batches are read the program ends and the file is complete.
I have been asked to add a feature where the entire "project" is inside of a JFrame with a new "upload" button. This would allow the user to run the program multiple times without having to open the JAR over and over again. If they select "Upload" they essentially start the program over.
Here is my main class:
package nachamultifive;
import java.util.ArrayList;
import javax.swing.JFileChooser;
import nachamultifive.Buffered_Reader_Writer.BatchCounter;
import nachamultifive.Buffered_Reader_Writer.FileValidation;
import nachamultifive.Buffered_Reader_Writer.MainWriter;
import nachamultifive.GUIs.FileHandling;
import nachamultifive.GUIs.ReturnBuilderGUI;
public class NachaMain
{
public static JFileChooser saveFile;//The output file save location.
public static JFileChooser uploadFile;//The uploaded NACHA file.
public static int batchTotal;//The total number of batches in the file.
public static ArrayList<String> batchHeaders;//An array of all batch headers.
public static int batchCounter;//The counter that displays the current batch number in sequence.
public static String location;
public static void main(String args[]){
FileHandling fHandling = new FileHandling();//The class that handles upload/save of files.
fHandling.getFile();//Allows the user to upload a file.
fHandling.setDirectory();//Allows the user to choose the save location.
saveFile=fHandling.saveFile;//Sets the file save location as static with the main class.
uploadFile=fHandling.uploadFile;//Sets the uploaded file as static with the main class.
BatchCounter bCounter = new BatchCounter();//The class that handles counting the batches.
bCounter.getBatches();//Counts the total number of batches.
batchTotal=BatchCounter.BatchTotal;//Sets the total number of batches as static with the main class.
batchHeaders=bCounter.batchHeaders;//Sets the batch header array as static with the main class.
MainWriter mWriter = new MainWriter();//The class that handles all writing functions for the new file.
mWriter.writeNacha();//Writes the output file.
location = MainWriter.location;
System.out.println("NachaMain Location=" + location);
FileValidation fValidation = new FileValidation();//The class that handles validating the output ACH file.
fValidation.validateNacha();//Method to validate the ACH file.
ReturnBuilderGUI gui = new ReturnBuilderGUI();//Class used for GUI's.
gui.displayFileOption();//Method used to display the ACH output and error report name.
gui.showSavedErrors();//Method to display the error report.
}
}
Essentially each of the classes calls modifies the input file. Inside of the mWriter class you will see this bit of code:
ReturnBuilderGUI gui = new ReturnBuilderGUI();//The GUI class.
ReturnBuilderGUI.displayGUI();//Calls the GUI to display the initial double list GUI.
Calling that class calls the entire GUI for that loop. (The mWriter class loops for each batch). When the ReturnBuilder class is called this is the basic code layout:
public static void displayGUI(){//Method to display the GUI.
final JButton createReturnButton = new JButton("Create Return");
createReturnButton.addActionListener(new ActionListener(){
public void actionPerformed(final ActionEvent ae){
if(verifyBatch==true){
initialScreenDecisions="NONE";//The user did not choose to add any entry details to the output list.
MainWriter.finishedCounter=true;//The boolean counter to trigger that the return is finished goes to true.
while(MainWriter.entryDetails.size()>0){//Removes all entry details from the input list.
MainWriter.entryDetails.remove(0);
}
while(output.size()>0){//Removes all entry details from the output list..
output.remove(0);
}
JOptionPane.getRootFrame().dispose();
}else {
JOptionPane.showMessageDialog(null, "No batches have been completed!");
}
}
});
final Object[] createR = new Object[] { "Confirm",createReturnButton };
int result = JOptionPane.showOptionDialog(null, getPanel(),"Return Builder", JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE, null, createR, "default");
System.out.println(verifyBatch);
//Creates a JOptionPane for the first GUI featuring 7 buttons and 2 lists..
}
The getPanel() method inside of that JOptionsPane calls the panel that has some buttons and lists. Depending on what the user chooses some more JOptionPane's will appear that give the user more options. When they are finished the initial mWriter class will loop again (assuming there are more batches in the input file) and the ReturnBuilder class will be called again restarting the process.
Now, I can't for the life of me figure out a way to make all this happen inside of a JFrame that remains before and after all these other things happen without having to restructure my code.
I don't know if I've given you guys enough information to work with. My only idea right now is that I feel like I need to create a JFrame in the ReturnBuilder class and add the JOptionsPane to it, but then when the ReturnBuilder class is called again later I'm sure the JFrame would just open again and be duplicate.
Any ideas?
It really looks to me that you need to use Cardlayout and flip to the next card at each step. When you are done, reset by flipping to the first card. CardLayout is cyclic, so it will flip to the first card automatically.
public class CardExample extends JFrame {
CardExample() {
JPanel main = new JPanel(new BorderLayout());
CardLayout cl = new CardLayout();
main.setLayout(cl);
for (int i = 0; i < 4; i++)
main.add(new StepPanel(i));
JButton next = new JButton("Next");
next.addActionListener(e -> cl.next(main));
add(main);
add(next, BorderLayout.PAGE_END);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
class StepPanel extends JPanel {
StepPanel(int i){
add(new JLabel("Step " + i));
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new CardExample());
}
}
All of this is instead of JOptionPanes, which is usually more comfortable for a step-by-step user interaction (see, for example, installers). Just customize each of what I called StepPanels and at the end you can use a "load and reset" button instead of "next".

How do i create a movie from a set of images using qtj and java?

I have a set of images i want to add one after another and create a movie. I will be using Quicktime for java for this(I'm on a mac).
I searched the web i have found lots of examples that show how to play movies using qtj, but i can't find any code snippets or tutorials showing how i can create a movie frame by frame using qtj?
I've done this through QTJ with the MovieMaker class from processing libraries (GPL). Processing is pure java, though it can hide it for beginners.
Small tutorial:
Download Processing, open it, go to Sketch -> Show Sketch Folder, create a folder called "data", and put all your images inside that folder, named "filename01.gif" through "filename09.gif". Paste the following code into the editor, and hit play:
/**
* Makes a QuickTime movie out of an array of images.
*/
import processing.video.*;
MovieMaker mm;
PImage[] imageFrames;
int index;
void setup() {
size(320, 240);
int numFrames = 9;
imageFrames = new PImage[numFrames];
for( int i = 0; i < imageFrames.length; i++ )
{
imageFrames[i] = loadImage( "filename" + nf(i+1,2) + ".gif" );
}
// Save uncompressed, at 15 frames per second
mm = new MovieMaker(this, width, height, "drawing.mov");
// Or, set specific compression and frame rate options
//mm = new MovieMaker(this, width, height, "drawing.mov", 30,
// MovieMaker.ANIMATION, MovieMaker.HIGH);
}
void draw() {
if( index < imageFrames.length )
{
// show the image
image( imageFrames[index], 0, 0 );
// Add window's pixels to movie
mm.addFrame();
index++;
}
else
{
mm.finish();
// Quit running the sketch once the file is written
exit();
}
}
This will create a file "drawing.mov" from your images in the sketch folder. If you go to file --> export application, and then open the sketch folder and navigate to the folder application.macosx/source or application.windows/source, there should be a .java file that has the actual code, which should look like this:
import processing.core.*;
import processing.xml.*;
import processing.video.*;
import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.text.*;
import java.util.*;
import java.util.zip.*;
import java.util.regex.*;
public class movie2 extends PApplet {
/**
* Makes a QuickTime movie out of an array of images.
*/
MovieMaker mm;
PImage[] imageFrames;
int index;
public void setup() {
size(320, 240);
int numFrames = 9;
imageFrames = new PImage[numFrames];
for( int i = 0; i < imageFrames.length; i++ )
{
imageFrames[i] = loadImage( "filename" + nf(i+1,2) + ".gif" );
}
// Save uncompressed, at 15 frames per second
mm = new MovieMaker(this, width, height, "drawing.mov");
// Or, set specific compression and frame rate options
//mm = new MovieMaker(this, width, height, "drawing.mov", 30,
// MovieMaker.ANIMATION, MovieMaker.HIGH);
}
public void draw() {
if( index < imageFrames.length )
{
// show the image
image( imageFrames[index], 0, 0 );
// Add window's pixels to movie
mm.addFrame();
index++;
}
else
{
mm.finish();
// Quit running the sketch once the file is written
//exit();
println( "done" );
}
}
static public void main(String args[]) {
PApplet.main(new String[] { "--bgcolor=#e0dfe3", "movie2" });
}
}
To use pure java, you'll need to use core.jar and video.jar from the processing application folder on your classpath, and then compile this java code. Here's a function reference and a javadoc for the processing library. Here are the javadocs for the MovieMaker class. If you want, you can see the source to the MovieMaker class.
HTH
There is an export related piece of sample code here:
http://developer.apple.com/samplecode/ImportExport/listing1.html
It shows how a single native QuickTime Movie can be opened for reading and then be passed on to a MovieExporter component to create a new QuickTime Movie from it.
For the code to import a file for as source for writing, see
void importMedia()
For the code to export the source to a QuickTime Movie, see
void run()
It should be possible to open an image file using the same approach, though, as long as the file format of the input file is supported by QuickTime (like f.e. BMP).
You should be able to write a sequence of image files using most of this code as well.
The only point which you will have to investigate is which method you'll have to call to append additional frames to an existing Movie. It might work using the same API, but most likely you'll need to use another call.
If you have to dig for another method you should be able to find it in the QT Java Reference Documentation located here:
http://developer.apple.com/Java/Reference/1.4/Java14API_QTJ/
It's a hack and most likely poor in performance, but it might actually work.
And... I never tried this (I am a QuickTime for Windows guy by trade) so: sorry, no warranty = ).
Edit: If you are looking for a way to write frames to a QT Movie using an existing input buffer instead of reading the data from file using the QT API, there should be APIs for
this as well. Just check out the reference documentation.
Edit 2: Actually it might be worthwhile to check out the C/C++ API Documentation here, as naming of components and calls seems to follow roughly the same naming conventions (i.e. this might help to dig for the calls of the Java API you need) and the C/C++ Docs seem to be more thorough in terms of providing Guides and How To's as a starting point. The C/C++ Docs can be found here:
http://developer.apple.com/referencelibrary/QuickTime/index.html
The most interesting sections should be
Import & Export
Compression & Decompression
Have Fun!

Categories

Resources