文章列表
 
您正在查看 "Java Algorithm" 分类下的文章

2008-11-20 22:04

/* The Reflection Test Class used to realize the functions of
   java.lang.reflect, referrenced by Corejava Volume I
   Display the fields, constructors, and methods, as well as annotations
   and exceptions respectively
   by kingmmxtj Nov 20, 2008
  
http://hi.baidu.com/kingmmxtj
*/

import java.util.*;
import java.lang.reflect.*;
import java.text.*;
import java.lang.annotation.Annotation; // pay attention to differ the java.text.annotation

public class ClassAnalyzer
{
    public static void main(String[] args)
    {
         // read the class u input
         String name;
         if(args.length > 0)
                name = args[0];
         else
         {
                System.out.println("Enter one class naem(e.g. java.uitl.Date): ");
                Scanner in = new Scanner(System.in);
                name = in.next();
         }
  
    try
    {
           // print class name and super class name
           Class cl = Class.forName(name);
           Class supercl = cl.getSuperclass();
           System.out.print("Class " + name);
           if(supercl != null) // if(supercl != null && supercl != Object.class)
           System.out.print(" extends " + supercl.getName());
           System.out.print("\n{\n");
          // leave 4 blank at the beginning
           System.out.println("    ****** Fields of the Class ******");
            printFields(cl);
           System.out.println();
           System.out.println("    ****** Constructors of the Class ******");
            printConstructors(cl);
           System.out.println();
          System.out.println("    ****** Methods of the Class ******");
            printMethods(cl);
           System.out.println("}");
     }
     catch(ClassNotFoundException e)
      {
              e.printStackTrace();
     }
   }
   
/* print all fields in the class
   @param cl a class
*/
     public static void printFields(Class cl)
     {
               Field[] fields = cl.getDeclaredFields();
     
               for(Field f : fields)
              {
                       Class type = f.getType();
                       String name = f.getName();
                       System.out.print("    " + Modifier.toString(f.getModifiers()));
                        System.out.println(" " + type.getName() + " " + name + ";");
                      // print all the annotations in the field
                       Annotation[] annote = f.getDeclaredAnnotations();
                        for(int i = 0; i < annote.length; i++)
                       {
                                 System.out.println("    // " + annote[i].toString());
                       }
                }
      }
    
/* print all constructors in the class
   @param cl a class
*/
    public static void printConstructors(Class cl)
     {
                 Constructor[] constructors = cl.getDeclaredConstructors();
     
               for(Constructor c : constructors)
               {
                        String name = c.getName();
                        System.out.print("    " + Modifier.toString(c.getModifiers()));
                        System.out.print(" " + name + "(");
       
                        // print parameter types
                        Class[] paramTypes = c.getParameterTypes();
                        for(int j = 0; j < paramTypes.length; j++)
                        {
                                 if(j > 0)
                                         System.out.print(", ");
                                 System.out.print(paramTypes[j].getName());
                         }
                        System.out.print(")");
                        // print the Exceptions in the constructor
                         Class[] ex = c.getExceptionTypes();
                        if(ex.length == 0)
                                      System.out.println(";");
                         else
                       {
                                   System.out.print(" throws ");
                                   for(int j = 0; j < ex.length; j++)
                                  {
                                               if(j > 0)
                                                         System.out.print(", ");
                                                System.out.print(ex[j].getName());
                                 }
                                  System.out.println(";");
                       }
                       // print all the annotations in the constructor
                      Annotation[] annote = c.getDeclaredAnnotations();
                        for(int i = 0; i < annote.length; i++)
                       {
                               System.out.println("    // " + annote[i].toString());
                       }
                 }
     }
    
/* print all methods in the class
   @param cl a class
*/
      public static void printMethods(Class cl)
      {
                Method[] methods = cl.getDeclaredMethods();
      
                for(Method m : methods)
               {
                         Class retType = m.getReturnType();
                         String name = m.getName();
       
                       // print modifiers, return value and method name
                        System.out.print("    " + Modifier.toString(m.getModifiers()));
                        System.out.print(" " + retType.getName() + " " + name + "(");
       
                       // print parameter types
                       Class[] paramTypes = m.getParameterTypes();
                        for(int j = 0; j < paramTypes.length; j++)
                       {
                               if(j > 0)
                                        System.out.print(", ");
                               System.out.print(paramTypes[j].getName());
                     }
                       System.out.print(")");
                      // print the Exceptions in the method
                       Class[] ex = m.getExceptionTypes();
                      if(ex.length == 0)
                                     System.out.println(";");
                        else
                     {
                                   System.out.print(" throws ");
                                   for(int j = 0; j < ex.length; j++)
                                  {
                                            if(j > 0)
                                                      System.out.print(", ");
                                            System.out.print(ex[j].getName());
                                    }
                                     System.out.println(";");
                     }
                    // print all the annotations in the method
                     Annotation[] annote = m.getDeclaredAnnotations();
                      for(int i = 0; i < annote.length; i++)
                   {
                              System.out.println("    // " + annote[i].toString());
                     }
             }
      }
}  

 
2008-11-14 20:53

声明Java Sound教程系列属于Sun MicrosystemJava Tutorials,由kingmmxtj2008115日开始翻译,并将在http://hi.baidu.com/kingmmxtj上发布。译者尊重Sun的权利,仅仅把文章用于学习交流。转贴请保留,谢谢!

原文地址http://java.sun.com/docs/books/tutorial/sound/sampled-overview.html

文件格式(File Formats

文件格式描绘了声音文件的结构,不仅包括了文件中原始音频数据的格式,也包括了可以存储进文件的其他信息。声音文件有多种格式,像WAVE(也称为WAV,通常在PC上常见)、AIFF(通常在Mac机器上)、AU(通常在UNIX系统上)。不同的声音文件类型有着不同的结构。例如,可能对文件“头部里的数据有不同的排放。头部包含了在文件实际音频采样之前的描述性信息。也有一些文件格式允许包含有描述性信息和音频数据的连续“块”(chunks)。头部包含了对数据格式的详细描述,数据格式说明了在声音文件中音频的存储方式。任何一种声音文件类型(file types)都可以包含多种数据格式(data formats)(虽然通常在一个给定文件里只有一种数据格式),而某些数据格式可以应用在具有不同文件格式的文件中。

Java Sound API中,一个文件格式有一个AudioFileFormat对象表示,包含有:

l         文件类型(file types)(WAVAIFF,等等)

l         文件的字节长度

l         文件中音频数据的长度(用帧来衡量)

l         一个AudioFormat对象,描绘了文件中音频数据的数据格式

AudioSystem类提供了在不同文件格式中读取写入的方法,和在不同数据格式中转换的方法。其中一些方法可以让你通过一种叫做的AudioInputStream流来访问一个文件的内容。AudioInputStreamInputStream类的子类,InputStream类把一系列字节封装来提供连续读取。相对于其父类,AudioInputStream类增加了对音频数据格式字节的深入(由一个AudioFormat对象来表示)。通过把一个声音文件当作AudioInputStream来读取,你可以直接访问采样点,而不需要区关心声音文件的结构(头部信息,块,等等)一个单一方法调用就可以给你所需要的关于数据格式和文件类型的所有信息。

什么是混频器(mixer)?

许多针对声音的应用程序编程接口(APIs)都使用音频设备(device)这个概念。所谓设备通常是一个物理输入/输出设备的软件接口。例如,一个声音输入设备可能代表一个声卡的输入功能,包括了一个麦克风输入、一个线路电平(line-level)模拟输入、或者可能会有一个数字音频输入。

Java Sound API中,设备由Mixer对象来表示,混频器的作用是处理一个或多个音频输入流和一个或多个音频输出流。在典型应用中,混频器实际上把多路输入流混成一个输出流。一个Mixer对象代表了物理设备的混频能力,像一个声卡可能会把从电脑上的各种输入混音,或者把来自应用程序并且需要输出的声音混音。

另一方面,一个Mixer对象也可以单边一个没有继承任何物理设备接口,完全由软件来实现的设备的声音混频功能。

Java Sound API中,像麦克风输入或者声卡等组件自身不被当作是设备,即不被当作是混频器(mixer),而是被当作混频器的输入或者输出端口(port)。一个端口通常提供混频器输入或输出的一个流(流可以多信道(multichannel),像立体声(stero))。混频器可以有多个端口。例如,代表一个声卡输出功能的混频器可能把多个音频流混在一起,然后把该混合信号送到连接该混频器的某个或这所有输出端口。这些输出端口可以是(举例)一个耳机插孔(headphone jack)、一个内置喇叭、或者一个线路级(line-level)输出。

理解Java Sound API中混频器的概念可以帮助我们视觉化一个真正的物理混频器控制台,像在现场音乐会和录音工作室里用的那些混频器。

一个物理混频控制台

一个物理混频器有许多的“路”(strips or slices),每一路代表一个音频信号进入混频器进行处理的路径。每一路有许多旋钮和其他可以控制该路信号音量和缩放(pan)(在立体图像stereo image中应用)(Panning解释:Panning is the spread of a monaural signal in a stereo or multi-channel sound field. A typical pan control is constant power. At one extreme, the sound appears in only one channel. In the middle, the sound is decreased in that channel by 3 dB, and the other channel is brought up to the same level, so that the overall sound power level is always constant.[1]――wikipedia)。混频器也有一条控制声音效果的总线,像混响(reverb),该总线可以连接到内置或者外置的混响单元。每条线路都有一个电压计来控制该条线路信号进入混响混合(reverbertated mix)的量。然后已混响混合(湿的“wet”)和来自线路“干的“(dry)信号进行混合。最后混频器把最终的混合信号发送到输出总线,通常是发送到录音器(或者是硬盘上的录音系统)或者是扬声器。

设想一个正在用立体声录音的现场音乐会。从许多麦克风连出来的电线(或者是无线连接)和台上的电子乐器都被接入混音控制台的输入端口。每一路输入都进入一条独立的strip中,如上所述。音响工程师决定了增益(gain),缩放(pan),和混响(reverb)的控制设置。所有strips和混响单元的输出被混合在一起进入2个声道。这2个声道直通混频器的2个输出,进入音乐会立体声录音器的输入。或者该2个声道通过放大器接到大厅的扬声器,这取决于音乐的类型和演奏厅的大小。

再设想一个录音工作室。在这里,每一种乐器或者人声被多轨录音机(multitrack tape recorder)录制到独立的轨道(track)上。在所有乐器和人声录音完成后,录音工程师开始“mixdown”来把录制的所有轨道的声音混合成一个2声道(立体声)录音,这种录音就是CD格式。在这种情况下,混频器的各路strip输入不在是一个麦克风,而是多轨录音中的一轨。同样,工程师可以使用strips上的控制按钮来决定每轨的音量(volume)、缩放(pan)、和混响(reverb)量。混频器的输出再次接入一个立体声录音机和一个立体声扬声器,与现场音乐会的例子差不多。

以上2个例子描绘了2种不同的使用混频器的情况:捕捉多输入声道信号,混合为较少的轨,保存混合声音,或者回放多轨录音的同时进行混频至较少的音轨。

Java Sound API种,一个混频器同样可以用来处理输入(捕捉音频)和输出(回放音频)。在输入的情况下,从混频器得到的要混频的音频源(source)是一个或多个端口(ports)。混频器把捕捉到的和混合的音频流送至目标(target)输出,目标通常为带有缓冲的对象,而从该对象中应用程序可以取回混频的音频数据。在音频输出的情况下,情况正好反过来。混频器的音频源是含有缓冲的一个或多个对象,而一个或多个应用程序可以把各自的音频数据写入到这些对象中;而混频器的目标输出将是一个或多个输出端口。

 
2008-11-08 15:14

声明Java Sound教程系列属于Sun MicrosystemJava Tutorials,由kingmmxtj2008115日开始翻译,并将在http://hi.baidu.com/kingmmxtj上发布。译者尊重Sun的权利,仅仅把文章用于学习交流。转贴请保留,谢谢!

原文地址http://java.sun.com/docs/books/tutorial/sound/sampled-overview.html

Sampled包综述

javax.sound.sampled包主要关注于音频传输,另一方面,Java Sound API关注于回放和捕捉。Java Sound API要处理的核心任务是如何吧某种格式的音频文件输入和输出系统。该核心任务包括打开输入和输出设备、管理充满实时(real-time)声音数据的缓冲区,也可以包括把多种音频流进行混频成一种流(无论是输入还是输出)。当用户需要对声音流进行播放、暂停、继续、或者停止时,声音输入或输出系统的传输问题需要正确处理。

为了支持基本音频的输入和输出,Java Sound API提供了各种方法,包括在多种音频数据格式间转换、读取和写入常用声音格式文件。但是API并不是一个易于理解和使用的针对所有音乐文件的工具包。针对Java Sound API的某种具体实现不需要支持某些额外的文件集或者数据格式转换。第三方服务提供者可以提供“插件”给现有的系统来实现支持额外的文件和格式转换。

Java Sound API可以处理流化缓存形式(streamingbuffered fashion)和内存的非缓存形式(in-memoryunbuffered fashion)的音频传输。本文的“流化”(streaming)主要是指对某种音频格式的实时处理。用另一句话说,一个音频流是差不多以相同速度到达的一段连续的将被处理(播放、录制等等)的音频字节。在所有数据到达之前,已经开始对这些音频字节进行处理。在流体模型中,特别是在音频输入而不是音频输出的情况下,你不必提前知道声音有多长或者数据是否完全到达。你只需要一次处理一个缓存区的音频数据,除非操所别终止。在音频输出的情况下(回放),如果你需要播放的声音数据太大,不能一次装入内存中,你仍然需要缓冲数据。用另一句话说,你把你的音频字节用块的形式传输个音频机器,由音频机器来关注准确的播放每一个采样。这种机制可以很容易确定每个块中有多少数据。

仅仅在回放的情况下,Java Sound API也允许非缓冲传输,前提是你已经把要处理的数据全部准备好而且这些数据可以一次在内存中放下。在这种情况下,不再需要应用程序来缓冲音频,虽然仍然可以使用缓冲的实时方法。用另一句话说,整个声音能一次提前载入内存来进行连续回放。因为所有声音被提前载入,回放可以立即开始,例如从用户按下开始按钮的一瞬间。相对于缓冲模型的回放需要等待缓冲区的第一次装满,上述的特性是非缓冲模型的一个优点。另外,内存缓冲模型轻易的使声音循环(loopcycled)或者从数据的某个任意特定位置来进行播放。

Java Sound API来进行播放和捕捉声音,你至少需要3样东西:格式化音频数据(formatted audio data)、一个混频器(mixer)、一条线路(line)。下面将综述这些概念。

什么是格式化音频数据(formatted audio data)?

格式化音频数据指任一种标准格式的声音。Java Sound API主要区分数据格式(data formats)和文件格式(file formats)。

数据格式(data formats

数据格式规定了如何解释原始”(raw)采样音频数据的一系列字节。原始采样音频数据包括从一个声音文件读取的数据、从麦克风输入捕捉的采样。例如,你可能需要知道一个采样由多少个位(bit)组成(声音最小单元的表示),或者你也需要知道声音的采样频率(每2个采样点之间的时间间隔)。当设置回放或捕捉时,你必须描述你要播放或捕捉的声音的数据格式。

Java Sound API中,数据格式由AudioFormat对象来表示,包括了以下几个属性:

l         编码技术,通常是脉冲编码调制(PCM

l         信道的数量(1代表单声道(mono),2代表立体声(stero)等等)

l         采样频率(每秒每个信道的采样点数)

l         每个采样点的比特数(每信道)

l         帧速率

l         帧的字节大小

l         字节顺序(大端(big-endian)还是小段(little-endian))

PCM是一种声音波形编码技术。Java Sound API包括2PCM编码:使用幅度线性量化(liner quantization of amplitude)和有符号或无符号整数值(signed or unsigned integer value)。线性量化意味着每个采样点存储的数值与该时刻原始声音的强度直接成比例(不包括噪声的影响),同样也与该时刻扬声器和耳膜的振动成相似的比例。例如,CD使用线性PCM编码音频。Mu-law编码和a-law编码是常用的非线性编码技术,这两种技术都提供了对音频数据的高压缩版本,主要用在电话技术和语音记录里。非线性编码通过非线性函数把原始声音幅度映射为一个存储的值,而该非线性被设计成相对与强信号可以提供给弱信号更多的幅度表示。

一个帧包含了一个特定时间所有信道所包含的数据。对于PCM编码的数据,帧就是所有信道里某个时间同步采样的集合,没有其他任何附加信息。在这种情况下,帧的速率相当于采样频率,而帧的字节长度相当与信道的数量乘以每个采样点的比特数除以一个字节所包含的比特数(8)。

对于其他的编码技术,一个帧可能包含除了采样点外的其他信息,而帧的速率可能与采样频率完全不同。例如,MP3编码技术(MPEG1 Audio Layer 3),虽然在现在的Java Sound API版本中没有提及,但是可以被Java Sound API的实现或者第三方服务提供者来支持。在MP3里,每一个帧包含一系列采样点的一捆压缩数据,而不仅仅是每个信道一个采样点。因为每一个帧都封装了一整段采样点,所以帧的速率比采样速率要慢。MP3帧还包含帧头(header)。除了头部,MP3帧的字节长度比包含相同采样点信息的PCM帧(不止一个帧)的字节长度要短。(毕竟,MP3的目的是取得比PCM数据压缩率更高的数据)对于MP3这种编码,其采样频率和采样点大小将参考PCM数据,即在被传输进入数模转换器(DAC)之前,编码数据实际上要先被转换为PCM数据。

 
2008-11-05 18:32

(1)创建jar包
   jar cf hello.jar hello   利用test目录生成hello.jar包,如hello.jar存在,则覆盖

(2)创建并显示打包过程
jar cvf hello.jar hello     利用hello目录创建hello.jar包,并显示创建过程
例:E:\\>jar cvf hello.jar hello
标明清单(manifest)
增加:hello/(读入= 0) (写出= 0)(存储了 0%)
增加:hello/TestServlet2.class(读入= 1497) (写出= 818)(压缩了 45%)
增加:hello/HelloServlet.class(读入= 1344) (写出= 736)(压缩了 45%)
增加:hello/TestServlet1.class(读入= 2037) (写出= 1118)(压缩了 45%)

(3)显示jar包
jar tvf hello.jar   查看hello.jar包的内容
指定的jar包必须真实存在,否则会发生FileNoutFoundException。

(4)解压jar包
jar xvf hello.jar   解压hello.jar至当前目录

(5)jar中添加文件
jar uf hello.jar HelloWorld.java     将HelloWorld.java添加到hello.jar包中

(6)创建不压缩内容jar包
jar cvf0 hello.jar *.class      利用当前目录中所有的.class文件生成一个不压缩jar包

(7)创建带manifest.mf文件的jar包
jar cvfm hello.jar manifest.mf hello
创建的jar包多了一个META-INF目录,META-INF止录下多了一个manifest.mf文件,至于manifest.mf的作用,后面会提到.

(8)忽略manifest.mf文件
jar cvfM hello.jar hello    生成的jar包中不包括META-INF目录及manifest.mf文件

(9)加-C应用
jar cvfm hello.jar mymanifest.mf -C hello/
表示在切换到hello目录下然后再执行jar命令

(10)-i为jar文件生成索引列表
当一个jar包中的内容很好的时候,你可以给它生成一个索引文件,这样看起来很省事。
jar i hello.jar     执行完这条命令后,它会在hello.jar包的META-INF文件夹下生成一个名为INDEX.LIST的索引文件,它会生成一个列表,最上边为jar包名。

(11)导出解压列表
jar tvf hello.jar >hello.txt   如果你想查看解压一个jar的详细过程,而这个jar包又很大,屏幕信息会一闪而过,这时你可以把列表输出到一个文件中,慢慢欣赏!

(12)jar -cvf hello.jar hello/*
   例如原目录结构如下:
   hello
     |---com
     |---org

你本想只把com目录和org目录打包,而这时jar命令会连同hello目洋也一块打包进。这点大家要注意。jar命令生成的压缩文件会包含它后边出的目录。我们应该进入到hello目录再执行jar命令。 注意:manifest.mf这个文件名,用户可以任指定,但jar命令只认识Manifest.mf,它会对用户指定的文件名进行相应在的转换,这不需用户担心。

 
2008-11-05 17:03

声明Java Sound教程系列属于Sun MicrosystemJava Tutorials,由kingmmxtj2008115日开始翻译,并将在http://hi.baidu.com/kingmmxtj上发布。译者尊重Sun的权利,仅仅把文章用于学习交流。转贴请保留,谢谢!

原文地址http://java.sun.com/docs/books/tutorial/sound/index.html

什么是MIDI

javax.sound.midi包包含传输和序列化MIDI事件的APIs,及从以上事件合成的APIs

相对于采样音频是其声音自身的一种直接描述,MIDI数据可以被认为是产生声音,特别是乐器声音的方法。MIDI数据,不像音频数据,不对声音进行直接描述。相反,MIDI数据描绘的是事件(events),这些事件影响了由支持MIDI的设备或乐器(像合成器)所产生的声音(或者动作)。MIDI数据与一个图形用户接口键盘或者鼠标事件相似。在MIDI里,事件可以被理解为对音乐键盘的各种动作,包括对该乐器设备上踏板的踩踏(pedal)、弦的滑动、开关打开关闭、按钮的旋转。这些事件不必需要相应的硬件设备来相应;他们可以有软件来模拟然后被存储在MIDI文件里。一个能创建、编辑、播放上述文件的程序称为序列器(sequencer)。许多电脑声卡包含MIDI控制音乐合成器芯片,而序列器将把MIDI事件发送给这些芯片。合成器也可以由软件完全实现。合成器解释他们收到的MIDI事件并产生音频输出。通常从MIDI数据中合成的声音是乐器声音(例如相对于语音信号)。MIDI合成器也能产生各种声音效果。

某些声卡包含MIDI输入和输出端口,通过这些端口外部的MIDI硬件设备可以连接(像键盘合成器或其他乐器)。从一个MIDI输入端口,一个应用程序可以接受外部MIDI音乐设备产生的事件。该程序可能用电脑内部的合成器来播放该乐器的演奏、把该事件保存为MIDI文件放在磁盘上、或者作为音乐注释文件来传递。一个应用程序可能会实用一个MIDI输出端口来播放外部乐器,或者控制其他外部设备,像录音设备。

下图描绘了基于Java Sound API下,某个可能的MIDI配置中,各个主要组件的功能关系。(与音频相似,Java Sound API允许不同的MIDI软件设备安装和连接,该图所示的系统仅仅是一个假想情景。)箭头表示了组件之间数据的流向。数据可以来自一个标准文件格式、或者(由右下角的key图所标识),来自音频、原始MIDI字节、或者时间标记的MIDI信息。

一个可能的MIDI配置

在该例中,应用程序通过加载存储在硬盘上的标准MIDI文件作为一个音乐记录来准备该乐器演奏(图左处)。标准MIDI文件包含了多轨(track),每一轨是一个时间标记MIDI事件的列表。大部分事件代表这乐曲的注释(调子和节奏)。该MIDI文件被读取,然后被软件序列器所“演奏”。序列器通过发送MIDI信息给其他设备来演奏曲目,像内部或外部的合成器。合成器自己可能会读取一个包含仿真某种乐器音色指令的音色库(soundbank)文件。如果没有读取,合成器将用任意已加载的音色指令来播放MIDI文件中的乐曲注释。

如上所述,MIDI事件在被送到MIDI输出端口的外部MIDI乐器之前必须转化为原始(非时间标记)MIDI。同样,从外部MIDI源(如图中的一个键盘乐器)进入电脑的原始MIDI数据必须被转化为时间标记MIDI信息,该信息进而能控制合成器,或者被序列器存储以背后用。

服务提供者接口(Service Provider Interfaces

javax.sound.sampled.spijavax.sound.midi.spi包包含了让软件开发者创建信音频或者MIDI源的APIs,而这些新的音频和MIDI源可以作为一个已存在的Java Sound API实现的“插件”(plugged in)而被单独提供。这里有一些添加服务(源)途径的例子:

l         一个音频混频器

l         一个MIDI合成器

l         一个能读取或写如一种新的音频格式文件或者MIDI文件的文件分析器

l         一个能转换不同声音数据格式的转换器

在某些情况下,服务是软件接口针对硬件设备功能的,像声卡,所以服务的提供者可能就是硬件设备厂商。在另外一些情况下, 服务纯粹以软件存在。例如,一个合成器或者混频器可以是针对声卡上芯片的接口,或者不依赖任何硬件支持来实现。

一个Java Sound API实现包含了基本服务集,然而SPI包允许第三方来创建新的服务。这些第三方的服务像内置服务一样被集成进系统。AudioSystem类和MidiSystem类扮演协调者的角色,使应用程序能显式或隐式的访问服务。通常现存的服务对于实用他们的应用程序来时是完全透明的。这种服务提供机制为建立基于Java Sound API的应用程序开发者提供益处,因为新的特性可以被加入到程序而不需要一个新版本的JDK或者JRE,而且,在多数情况下,甚至不需要重新编译该应用程序本身。

 
2008-11-05 16:51

声明Java Sound教程系列属于Sun MicrosystemJava Tutorials,由kingmmxtj2008115日开始翻译,并将在http://hi.baidu.com/kingmmxtj上发布。译者尊重Sun的权利,仅仅把文章用于学习交流。转贴请保留,谢谢!

原文地址http://java.sun.com/docs/books/tutorial/sound/index.html

Sound开始

Java Sound API是一种低级的API,用来处理和控制声音媒体的输入和输出。声音媒体包括了音频数据和乐器数字化接口数据(MIDI)。Java Sound API针对声音输入和输出通常所要求的性能提供了显式控制,并提供了一种提高扩展性和灵活性的框架。

Java Sound API实现了应用程序开发者的广泛需求。可能的应用程序领域包括:

l         通信架构程序,例如会议和电话技术

l         最终用户数据传递系统,例如媒体播放器和使用流格式的音乐

l         互动性的应用程序,例如游戏和使用动态内容的网站

l         数据流创造和编辑

l         开发工具,工具包,和实用程序

Java Sound API提供Java平台下最底层的声音支持,它提供应用程序大量针对声音操作的控制,并且这都是可以扩展的。例如,Java Sound API提供安装、访问、和操控系统资源的各种机制,像音频混频器(mixer)、MIDI合成器(synthesizer),或者其他的音频和MIDI设备、文件读取器(reader)、文件写入器(writer)、声音格式转换器(converter)。Java Sound API不包括复杂的声音编辑器或者图形化工具,但是它提供了建立这些应用的能力。Java Sound API强调的是大部分最终用户都所期望的对声音的底层控制。

Java Sound API包括了对数字音频和MIDI数据的支持。这2个主要模块的功能在以下独立的包内:

l         javax.sound.sampled

该包详细描绘了对数字(采样)音频的捕捉(capture)、混音(mixing),回放(playback)的各种接口。

l         javax.sound.midi

该包提供了MIDI合成(synthesis),序列化(sequencing),事件传输(event transport)等接口。

另外2个包允许服务提供者(service providers)(与应用程序开发者相对而言)创建自定义的软件组件,来扩展某种Java Sound API具体实现的功能:

l         javax.sound.sampled.spi

l         javax.sound.midi.spi

本页介绍了采样音频系统、MIDI系统,SPI包。每一个包将在后续章节中进行详细介绍。

―――――――――――――――――――――――――――――――――――――――

注意:Java平台的某些APIs也有与声音相关的。Java Media Framework API (JMF)是一种高级API,现在作为Java平台的一种标准扩展。JMF详细描绘了一个统一的架构、消息协议、和捕捉、回放以时间为基准的媒体的编程接口。 JMF提供了一种针对基本媒体播放器应用程序的简单解决方案, 同样也允许不同媒体类型之间的同步,如音频和时频的同步。另一方面,集中于声音处理的程序可以从Java Sound API中获得便利,特别是那些需要更多高级特性的程序,像微调控制缓存音频回放的能力或者直接操控一台MIDI合成器。其他与声音相关的Java APIs包括Java 3D、电话技术和语音的APIs。所有上述的这些与声音相关的APIs的某种实现都可能在其内部用到某个Java Sound API的实现,但这不是必须的。

―――――――――――――――――――――――――――――――――――――――

什么是采样音频?

javax.sound.sampled包处理数字音频数据,这种数据在Java Sound API里即为采样音频。采样是对一个信号的连续快照(snapshots)。对音频而言,信号就是一段声波。麦克风把原始的信号转化为相关的模拟电信号,然后AD转换器把该模拟信号转化为一种采样的数字信号。下图为声音录制中的一小段时间。

一段采样的音频波形

该图在纵轴上画出了声波的幅度,水平轴为时间。该模拟声波的幅度在某个频率下等间隔的被测量,最后形成的离散采样点(图中的红色数据点)组成了数字音频信号。图中中间的水平线代表幅度为0;线上的点为正值采样点,线下的为负值。数字信号逼近某个模拟信号的精度取决于其在时间上的分辨率(采样频率)和其量化标准(幅度上的分辨率,每个采样点用几位数字来表示)。作为一个例子,CD上存储的音频数据是每秒采样44100个点、用16位的数字来表示每个采样点的数值。

“采样音频”(sampled audio)这个术语在这里比较宽泛。一个声波可以按照一个离散间隔来采样但仍然保留其模拟信号的形式。然而在Java Sound API里,“采样音频”的意思就是“数字音频”(digital audio)。

特别需要注意的是,电脑上的采样音频来自于声音录制,但是相应的声音也可以由各种其他声音信号合成的(例如合成一个拨号电话的声音)。“采样音频”在这儿指的就是这种合成性的声音,而不是原始的声音信号。

Java Sound API并不针对某种音频硬件配置;它被设计成允许不同音频组件安装在系统上并且都可以被API访问。Java Sound API支持常用的功能,像声卡的输入和输出(例如声音文件的录制和回放)及多种音频流的混响。下图是典型音频系统架构示意图:

  

一个典型音频系统架构

在这个图中,像声卡这种设备有许多的输入和输出端口,而混响则由软件提供。混频器可能通过读取一个文件、网络上的流,应用程序产生的数据、及MIDI合成器产生的文件来接收数据。混频器把音频输入的各种信号组合成一个单一的流,该流可以被送到输出设备进行输出。

 
2008-09-22 21:22

September 22, 2008结束了预谋了一段时间的scjp310-055,终于给看了好多年前言的java的自己画上了个方框。94%Pass,其实也就答了1小时题,如同前人所说:答题很简单,可是准备考试确实让我痛苦了一阵子。思路还是比较传统:scjp学习指南至少看2遍,TestKiller的模拟题做2遍,vce的模拟题做2遍,ActualTest的模拟题做2遍。行了,够了,你可以出310-055的试题了。其中最大的感触是明白(线程,泛形,集合,内部类是难点)compilation failsRuntimeException的问题,你要明白编译器的语法规则,同时要明白有些东西(如override的polymorphism)是编译器无法检查的,只有在运行是才能知道是否有错误Exception。考试不是目的而是手段,拿到scjp的最大感触是scjp结束了,可java刚刚开始。

 
2008-09-19 18:20

第一次利用NetBeans写了一个GUI计算程序,确实佩服Netbeans的强大。由于以前一直没有做GUI,对Swing类也一直没有接触,只是用UltraEdit来写代码用JDK来编译。翻看了一下关于Swing的书籍了解的容器和组件的关系及事件,没想到在NetBeans里直接用拖放就能解决:容器,布局,边框,组件及其所有的属性字段,性感。唯一需要添加的就是事件,右键点击组件,选择事件,然后在TODO里写入相应代码。Cool!从没用Swing到只用2天就能写一个GUI程序,喜欢NetBeans不得了,哈哈哈哈!唯一的问题就是事件还不熟,而感觉对于NetBeans唯一不够智能化的一点就是关于组件可能的相应事件没有提示。

 
2008-09-06 16:34

import java.io.*;
//只要你不是利用args数组就必须要用io包,这里没有使用文件操作
//只要涉及到io操作必须要用异常控制:try{}catch{}防止出错

public class AsUWish{
    public static void main(String[] args){
    try{
    //这是异常输入,你就理解为把这段代码用try包裹意味着可能会出现某种错误
        System.out.println("Input anythings U wanna!\n");
        //提示输入
        InputStreamReader isr = new InputStreamReader(System.in);
        //新建一个输入流读取器,并把标准键盘输入System.in的输入流转入该读取器中
        BufferedReader br = new BufferedReader(isr);
        //在输入流读取器外部在包装一个缓存读取器,其实用文件读取器就可以实现读入功能,但是要一个字符一个字符读取
        //所以如果直接实用isr的read方法必需要建立一个字符数组来保存你的输入流,如
        //char[] myin2 = new char[1000000]数组必需要大到能保存我们的流

        String myin;
        myin = br.readLine();
        //利用缓存器特有的方法readLine()直接读取一个文本行,并存为一个字符串,不需要char数组
        System.out.print("\n" + myin);
        br.close();
        //所有io读取器读完都要关闭释放io资源
       }catch(IOException e){
       //与try配套,如果上述代码有问题则在这里用catch把这个问题--IOException给抓住,然后下一句给予解决
            e.printStackTrace();
            //这就是解决方案:啥也没做,就是把错误信息打印在屏幕上
        }
     }
}

 
2008-06-24 8:35

scjp读书笔记3:Operators and Operands

1.元数据值和引用值都能运用强制转换,不允许在元数据类型和引用类型之间运用强制转换;布尔值不能强制转换为其他数据值,反之亦然;引用字null可以强制转换为任何引用类型
2.宽元数据转换:
            byte(8)--->short(16)
                                             ----->int(32)--->long(64)--->float(32)--->double(64)
                             char(16)
3.窄元数据转换:char与2种整型,short和byte之间的任何转换都为窄转换,因为char为无符号而byte或short为有符号
4.沿继承层次向上的转换叫做宽引用转换(向上转型),反之为窄引用转换(向下转型)
5.一元数值升级运用隐含宽转换将操作数类型比int窄的(byte,short,char等)转换为int,不影响其他数值类型的操作数
6.二元数值升级,对于两个操作数中的较宽的数值类型T,如果T比int宽,则两个操作数都被转换为T,否则这两个操作数都被转换为int;这意味着byte,short,char至少会被转换成int
7.赋值复制引用的同时也创造了别名:赋予引用不会对右侧变量所代表的那个源对象创建一份副本,引用赋值不会将源对象的状态复制给左侧引用变量所代表的那个对象(左侧引用变量最初代表的对象),引用赋值只不过将右侧变量的引用赋值赋予左侧变量而已,于是它们会代表同一个对象
8.多重赋值:int[] a={1,2,3,4,5,6};
                      int index=4;
                     a[index]=index=2;
   计算如下:a[index]=index=2;
                    a[4]=index=2;//[]运算符优先级最高
                    a[4]=(index=2);//赋值运算符的右结合性,此时index为2
                    a[4]=2;
9.整型拓宽成浮点型时会导致精度丧失,数的精度与其有效数位有关而不是其数量级问题;浮点型转换为整型会产生截断
10.一元运算符为右结合性,二元运算符为左结合性
11.整型算术运算除0或除0求余将导致ArithmeticException,对于int toobig=Integer.MAX_VALUE+1;将产生回卷;对于浮点算术运算,两个很大的浮点数相加或相乘或除0会得到常值Infinity或-Infinity
12.浮点算术运算的上溢和下溢(Float或Double通用)
                            .
                             .
                             .
   Double.POSITIVE_INFINITY     正无穷大
                             .
                             .
    --------------->上溢
           Double.MAX_VALUE ----
                             |
                             |
           Double.MIN_VALUE ----
                        正       0.0 ------------>下
                            ----
                        负      -0.0 ------------>溢
          -Double.MIN_VALUE ----
                             |
                             |
          -Double.MAX_VALUE ----
                            .    ---------------->上溢
                             .
    Double.NEGETIVE_INFINITY    负无穷大
                             .
                             .
13.(-0.0==0.0)为true
14.运算在数学上没有结果如-1的平方根,浮点型的0.0/0.0均返回NaN。NaN与其他任何值(包括NaN)之间的任何比较(出了不等性比较!=)都会返回false,而与不等性比较总会返回true;检查某个值是不是NaN时,推荐使用两个封装器类(java.lang.Float和java.lang.Double)中定义的静态方法isNaN()
15.关键字stictfp用来强行实施严格的浮点运算,该修饰符可用来修饰接口,类和方法,但这种严格性不会派生在子类或子接口中
16.double d1=12/8;//d1=1.0操作数是整型时进行整型除法,即使结果存放在浮点型变量中;如果任一操作数是浮点型,则进行浮点除法
17.对于求余运算符%,当为整型运算时x%y==x-(x/y)*y(只有被除数为负时余数才能为负,与除数的正负无关);当为浮点运算时r==a-(b*q)(q为(a/b)的整型商,建议用long(a/b)来进行强制转换)
18.一元算术运算符(-/+)的唯一操作数会运用一元数值升级,即对byte,short,或char型运用时,该操作数会升级为int,如果不满足隐含窄元变换要进行明确的强制转换byte b=3; b=(byte) -b;//(-b)被升级为int,需要显式强制转换
19.二元算术表达式数值升级:§单字节数值,||双字节数值
   ( d    *        i )     +    ( f     *     -b )      -    ( c     /    s )
     |               |                 |            |                   |          |
   double       int           float       byte          char      short
     |                ||                |            §                ||            ||
     |           double           |            int              int         int
     |                 |               |             ||                |             |
     |                 |               |           float             |              |
     |                 |               |              |                |             |
     ---------------                -----------                ------------
            |                                |                              |
        double                         float                         int
            |                                 ||                             ||
            |                             double                        ||
             |                                 |                              ||
             ----------------------------                             ||
                             |                                               ||
                        double                                      double
                             |                                               |
                             --------------------------------------
                                                   |
                                              double
20.short h = 40;
     h = h+2; //error,h+2 is int not short, explicit cast required
     h = (short)(h+2); //right (2)
     h += 2; //right, evaluated as (2)
21.System.out.println(0x10+10+010);//34,按照10进制输出
22.boolean不能被强制转换为任何非boolean类型
23.对于所有引用型的操作数而言,其字符串表示是通过引用对象的toStirng()方法构造而成;例如在在用二元字符串连接符+时,整型值100会隐含转换成字符串“100”,通过方法new Interger(100).toString();
24.++/--无法进行结合,假定a是一个变量,无法写出(++(++a)),因为++运算符的任何操作数必须是变量,而(++a)得到的是一个值。当操作数是char,byte,short时,则会进行二进制数值升级和隐含窄转换
25.比较浮点数的相等性要注意,因为无穷浮点数只能以约数的形式放在有限的位数中,所以(1.0-2.0/3.0==1.0/3.0)是false
26.对象值的相等性要区别与对象引用的相等性,或许对象值(即对象状态)相同的,但对于各自使用new创建的对象引用来说是不相等的,除非对象a的引用也赋值给对象b。如果类没有覆盖来自Object类的equals()方法,对该方法而言,对象值的相等性等同于对象引用的相等性
27.条件运算符&&和||类似与逻辑运算符&和|,不过条件运算符的计算要进行短路计算;条件运算符只能用于boolean操作数,对应的逻辑运算符还可以用在元运算中的整型操作数;当右侧操作数有条件的依赖于左侧操作数时,我们运用条件运算符&&和||,如果两侧的操作数都需要计算则用逻辑运算符&和|
28.关于移位运算:移位距离的计算就是对右侧操作数和一个掩码求AND,如果左侧操作数升级后为int,则掩码为0x1f(31),如果升级为long,则掩码为0x3f(63)。这意味着当遇到int左侧操作数掩盖右侧操作数的低5位,移位距离在0~31之内,遇到long左侧操作数时掩盖右侧操作数的低6位,移位距离在0~63之内。由于char,byte,short等操作数都会升级成int,因此运用移位运算符的结果总是int或long。无论是操作数的升级还是移位距离的决定,操作数本省不受移位运算符的影响,而移位赋值运算符可以改变变量的值。对于<<和>>都是用符号位填充
29.条件表达式可以嵌套,符合右结合性,(a?b?c?d:e:f:g)->(a?(b?c?d:e:f):g)->(a?(b?(c?d:e):f):g)
30.参数传递:
   形参的数据类型---------->传递的值
   元数据类型                    元数据值
   类类型                             引用值
   数组类型                         引用值
31.当实参是元数据类型的变量时,该变量的值在方法调用期间会复制给形参,由于形参是方法的局部变量,因此对形参作出的任何修改在调用结束后都不会影响到实参
32.形参只会改变那个将其引用值传递给方法的对象的状态,即对象值(对象状态)可以通过形参改变,但对象引用无法改变
33.不管形参的类型是啥,java中的参数传递是传值调用,不是引用调用,后者允许通过形参改变实参的值
34.final参数修饰形参,使得该变量在其生存期内无法改变其中的值,这里指的是final修饰引用值,而不是该参数代表的对象,对象的状态可以像以前一样得到修改。如(final ClassA a)a.change="ok";//允许a=null;//错误
35.main方法的形参是一个String对象的数组,通过arg[0], arg[1]...arg[args.length-1]依次访问

 
2008-04-19 9:12

1:标志符可由字母(unicode字母,包括latin字母),数字,连接标点(_下划线),任意货币符号($,¥...)组成.但标志符的第一个字符不能是数字,且关键词保留词不能成为标志符
2:java中的关键词abstract assert boolean break byte case catch char class continue default do double else extends final finally float for if implements import instanceof int interface long native new package private protected public return short static strictfp super switch synchronized this throw throws transient try void volatile while
3
:java中的保留词null true false
4:java中的保留但尚未使用的关键词const Goto
5
:字代表一种常量值,意味着字的值在程序中保持不变,包含整数字,浮点字,字符字,字符串字,及null空引用
6:整形字的默认数据类型是int,加上后缀L或l即为long,无法直接定义给出short或byte型字.java不支持二进制表示法的字,只支持十进制,八进制(前缀0),十六进制(前缀0x或0X)
7:浮点型字的没人数据类型是double,添加后缀D或d显式规定,或后缀F或f规定为float.对于科学计数表示法小数点及幂是可有可无的,但至少给出1位数字
8:java中的字符按16位的Unicode字符集来表示,包含了8位的ISO-Latin-1字符及7位的ASCII字符.所有的Unicode字符都可以表示成前缀\u的4位16进制数.\uxxxx表示法可以在源代码中的任何地方使用,表示其字符,但源代码中不能用4位16进制数来代替换行及回车,将会导致编译错误,必须用转义序列.区别与字符串型字, 在字符串型字中可以出现Unicode值来代替转义序列
9:转义序列也可以用\ddd定义的八进制的字符型字来表示,且不能超过\377,即只能表示前256个字符
10:字符串型字必须在引号之内且不能跨行,都是String类的对象
11:单行注释//....至行尾,多行注释/*....*/,归档注释/**....*/,注意嵌套多行注释只会忽略其中注释符导致注释不匹配编译错误
12:元数据类型值不是对象,但对应都有其封装器类,可以把元数据类型值表示成对象
13:

           Boolean类型- boolean 宽度不可用

   原型-

                                                            Character类型- char 16位
                                     Integral类型-
                                                                                byte 8位
                                                                               short 16位
                                                           integer类型- int 32位
                                                                              long 64位

            Numeric类型-

                                                                      float 32位
                                     Floating-point类型-
                                                                     double 64位  


14:java中,变量只能存储元数据类型的值或指向对象的引用(也叫引用变量)
15:Pizza smallone;//上述声明并没有创建任何Pizza类对象,声明只不过是创建了一个变量smallone来存储指向Pizza类对象的引用.Pizza smallone = new Pizza("hot");//此声明创建了一个pizza类的对象但不是smallone(有点搞不清吗?:)关键词new和构造函数调用Pizza("hot")(进行了初始化)和在一起创建了一个Pizza类对象,指向这个新建对象的引用则赋予了变量smallone,所以smallone是新建对象的引用变量,而不是新建的对象本身
16:字段的默认值,布尔型为false,字符型为'\u0000',整型为0(long为0L),浮点型为0.0F或0.0D,引用型为null
17:局部变量保持未初始化,除非进行显式初始化,一个变量初始化与否不受变量类型的影响.必须在运行方法时显式初始化所创建的局部变量(局部引用变量和元数据类型变量),否则编译错误
18:java源文件的顺序结构必须按照如下格式安排
   //part 1 (optional) Package declaration
   Package com.shit.bullshit.allbullshitPackage;
   //Part 2 (zero or more) import declaration
   import java.io.*;
   import java.util.*;
   //Part 3 (zero or more) top-level class and interface declaration
   Public class Newshit{ }
   class Aclass { }
   interface Ione { }
   ......
   //end of file
   //类和接口的定义次序任意,类声明+接口声明=类型声明
   所以,空文件也是合法的java源文件
19:java2强制规定,每个源文件最多定义一个公共类,一旦定义,源文件名必须与这个公共类相符,所以以上文件名为Newshit.java
20:main()方法的可访问性必须为public,且为类的静态方法,且没有返回值,只有一组String对象作为它唯一的形参, 但上面各项并不排斥其他修饰符或throws子句,所以main()方法声明如下
    xxxx xxxx public static void main(String[] xxxx){ }
    //public与static无次序问题
    //通常为String[] args等价与String args[]

 
2008-04-16 14:58

:记得高中时对java的迷恋,只是像地下工作者一样偶尔拿出java core瞅2眼,仍旧记得当时的scjp是rmb2750,只是那时都是微软的认证到处肆虐,知道scjp的人甚少,因为当时的java似乎还在与自己的定位搏斗.一晃近10年了,scjp便宜了许多rmb1200,也成为programmer行业的通行证.重新拾起曾经熟悉又陌生的语言,心中有说不出的滋味,似乎又是在不合适的时间地点再次碰到了亲密的朋友.这一次,需要给自己,给自己曾经的懵懂,画上一个虽不完美,但还算光滑的圆.

参考书目:Java认证考试指南, Sun认证Java 2程序员学习指南, Java 2复习重点及模拟试题, Core Java 2卷一:基础知识, scjp复习指南(Unix Center提供)

//一个可以实现压入,弹出字符的堆栈抽象, 类名:CharStack
public class CharStack {

   //Fields字段:包括实例变量+静态变量:反映类或对象的属性

   //Instance variables实例变量:属于对象
   private char[] stackArray; //数组实现堆栈
   private int    topofStack; //栈顶元素

   //Static variable静态变量:
   private static int counter; //只属于类而不属于类的实例化--对象, counter用来统计该类创建对象个数

   //Constructor构造函数:
   public CharStack(int n) {
      stackArray = new char[n];
      topofStack = -1;
      counter++;
    }

//Methods方法:包括实例方法+静态方法:反映类和对象的行为

   //Instance Method实例方法:属于对象
   public void push(char element) { //向堆栈压入一个字符
      stackArray[++topofStack] = element;
    }
   public char pop() { //删除并返回栈顶元素
      return stackArray[topofStack--];
    }
   public char peek() { //查看栈顶元素并不删除
      return stackArray[topofStack];
   }
  
public boolean isEmpty() { //判断栈顶是否为空
     return topofStack < 0;
    }
   public boolean isFull() {
//判断栈顶是否为满
      return topofStack == stackArray.length - 1;
    }

   //Static Method静态方法:只属于类而不属于对象
   public static int getInstanceCount() { //返回计数器的值
      return counter;
   }
}

1:类成员包括字段与方法,分别为类的属性与行为
2:实例成员属于对象,静态成员属于类
3:类的静态成员可以通过类名及对象引用加以访问,但实例成员只能通过对象引用加以访问,int count = CharStack.getInstanceCount();或者CharStack stack1 = new CharStack(10); int count = stack1.getInstanceCount(); 而char c = CharStack.pop();是错误的
4:class PrintableCharStack extends CharStack为继承, CharStack为超类, PrintableCharStack为子类, 2者为一般化与特殊化的关系, PrintableCharStack扩展了CharStack, 但由于CharStack的字段可访问性为private,子类P无法访问进而继承父类C的某些字段或方法,需要把private改为protected
5:聚合无处不在,因为对象不能包含其他对象只能通过引用来支持其应用, 这些引用字段便聚合了某些其他对象的具体属性和方法
6:java的代码必须封装在类中
7:java只有2种值:对象引用和元类型的原子值
8:引用代表那些根据类创建的对象,对象只能通过引用加以操作,java中的对象不能包含其他对象,它们只能拥有指向其他对象的引用,对象的删除是有运行时系统管理的
9:java程序必须有一个定义了main方法的类, 且必须为public, 声明如下public static void main(String[] args){....}, 该方法是任何程序的执行起点
10:#javac Hello.java
   #java Hello

 
 
   
 
 
文章存档
 
     
 
最新文章评论
  

x=-pi:0.05:pi; plot(x,sin(x)*cos(x),'o');
 

请大神指教
 

m=1:255; k=-500:500; w=(pi/500)*k; R=k/500; r0=0.9141; r2=r(257:511); X=r2*cos(
 

 

>> a=[2,3,-1;8,2,3;45,3,9]; >> b=[2,4,23]; >> x=inv(a)*b Error using * Inner ma
   
帮助中心 | 空间客服 | 投诉中心 | 空间协议
©2012 Baidu