Предисловие

Эта серия уроков предназначена для того, чтобы научить вас использовать Java Sound API. Первый урок в этой серии был озаглавлен "Java Sound API, Введение.. ". Предыдущий урок назывался "Java Sound API, создание, воспроизведение и сохранение синтетических звуков ."

Два типа аудиоданных

Java Sound API поддерживает два разных типа аудиоданных:

  • Оцифрованные аудиоданные
  • Данные цифрового интерфейса музыкальных инструментов (MIDI)

Эти два типа аудиоданных очень разные. На данный момент я концентрируюсь на дискретизированных аудиоданных. Я отложу обсуждение MIDI на потом.

Совет для просмотра.

Возможно, вам будет полезно открыть еще одну копию этого урока в отдельном окне браузера. Это упростит вам перемещение вперед и назад между различными списками и цифрами, пока вы читаете о них.

Материал из предыдущих уроков.

В предыдущих уроках этой серии было показано, как:

  • Создавать, воспроизводить и сохранять синтетические звуки, используя функции пакета java.nio для помощи в манипуляциях с байтами.
  • Использовать методы класса AudioSystem для написания более надежных аудиопрограмм.
  • Воспроизводить аудиофайлы, включая те, которые вы создали с помощью программы Java, и те, которые вы получили из других источников.
  • Сохранять данные с микрофона в аудиофайлы любого типа по вашему выбору.
  • Захватывать данные микрофона в объект ByteArrayOutputStream.
  • Использовать Sound API для воспроизведения ранее записанных аудиоданных.
  • Определять микшеры, доступные в вашей системе.
  • Указывать конкретный микшер для использования при получении аудиоданных с микрофона.
  • Узнали об использовании линий и микшеров в Java Sound API.

Этот урок покажет вам, как выполнять преобразование файлов между различными типами аудиофайлов.

Анонс

Тип аудиофайла отличается от кодирования звука.

В последние годы было определено множество типов аудиофайлов, включая AU-файлы, AIF-файлы и WAV-файлы. Однако при попытке определить, подходит ли конкретный аудиофайл для конкретного приложения, простого знания типа файла недостаточно. Вы также должны знать, как кодируются аудиоданные в файле.

Проще говоря, спецификация типа файла указывает, как байты физически расположены в файле. Спецификация кодирования указывает, как аудиоинформация размещается в байтах. Не все типы файлов могут вместить все кодировки. Однако многие типы файлов могут содержать несколько различных кодировок.

Как оказалось, типы файлов являются менее сложными из двух тем. Я буду иметь дело с типами файлов в этом уроке. Я начну разбираться с кодировками в следующем уроке.

Информация о различных типах файлов.

Ниже приведены описания некоторых типов файлов, поддерживаемых Sun Java, из Высокотехнологичного словаря типов файлов:

  • AU - Формат звукового файла, используемый на Sun Microsystems или других компьютерах UNIX.
  • AIF - Формат файла обмена аудио или AIFF (расширение имени файла). Формат, разработанный Apple Computer для хранения высококачественных аудиофайлов и информации о музыкальных инструментах. В нее можно играть на ПК и Mac. (Обратите внимание, что Sun Java API обрабатывает общее расширение имени файла для этого типа как AIF.)
  • WAV - Звуковой файл. (Как видите, словарь HighTech Dictionary не особо много говорит об этом типе файлов. Я добавлю, что большинство звуковых файлов, предоставляемых Microsoft при типичной установке Windows, являются файлами WAV.)

Описание формата.

Вы можете просмотреть техническое описание формата файла AU, включая информацию о том, как расположены байты в файле, в в заголовочном файле для аудио,. au.

Вы можете просмотреть аналогичное техническое описание для формата файла AIFF здесь. Наконец, вы можете просмотреть техническое описание формата файла WAV в каноническом формате файла WAVE.

Конечно, если вы запустите свою поисковую систему Google, вы также сможете найти множество других описаний этих и других форматов файлов.

Общая информация о оцифрованном звуке.

Вы найдете очень интересную информацию об сэмпл опубликованные Марка сапоги-Ebenfield в звуковые форматы. На веб-сайте представлен следующий фактоид, касающийся качественной музыки на компакт-дисках.

"На музыкальном компакт-диске музыка сэмплируется на частоте 44,1 кГц с использованием 16-битных слов или 705 600 бит для каждой секунды звука. При 8 битах к байту это означало бы, что 1 секунда качественной музыки CD заняла бы 88 200 байт или 88 КБ вашего гибкого диска, который содержит 1,2 Мб данных. Это означает, что вы можете держать 13 секунд музыки качества CD на дискете- (несжатой)!"

Если вышеприведенная оценка верна, то для содержания типичной трехминутной песни в несжатом формате CD потребуется около пятнадцати дискет. (Этот факт будет более важен в будущих уроках по кодированию, чем в этом уроке.)

Обсуждение и пример кода.

Пользовательский интерфейс.

Пользовательский интерфейс этой программы очень прост. Эта программа предназначена для выполнения из командной строки следующим образом:

Использование: java AudioFileConvert01 inputFile outputFile

Программа называется AudioFileConvert01.

Прежде чем перейти к деталям программного кода, я опишу программу и покажу вам несколько примеров, полученных при запуске программы.

Эта программа демонстрирует возможность написания Java-программы для преобразования одного типа аудиофайлов в другой тип аудиофайлов. Запустите программу, введя в командной строке следующее:

java AudioFileConvert01 inputFile outputFile

Типы входных и выходных файлов.

Тип создаваемого выходного файла зависит от расширения имени выходного файла, например au, wav или aif.

С другой стороны, тип входного файла не зависит от имени или расширения входного файла.  Фактический тип входного файла определяется программой независимо от имени файла или расширения, данного этому файлу.

Воспроизведение выходного файла.

Вы должны быть в состоянии воспроизвести выходной файл с любым стандартным медиаплеером, который может обрабатывать тип файла, или с программой, написанной на Java, такой как программа с именем AudioPlayer02, которая была разработана в предыдущем уроке.

Операционные примеры.

В следующих параграфах показаны примеры экранных выходов для различных типов входных и выходных файлов. Обратите внимание, что разрывы строк были вставлены вручную, чтобы заставить материал поместиться в этом узком формате публикации.

Допустимый входной файл с недопустимым расширением файла.

В первом примере, показанном на Рис. 1, допустимый входной wav-файл с именем ringout был вынужден иметь недопустимое расширение .txt. Однако программа успешно определила тип файла wav на лету, и файл wav был успешно преобразован в файл au.

(Вы можете распознать основное имя этого файла как один из звуковых файлов, обычно включенных в стандартную установку Windows. Я просто сделал копию файла с именем ringout.wav и изменил расширение перед запуском этого эксперимента.)

java AudioFileConvert01 ringout.txt junk.au
 Input file: ringout.txt
 Output file: junk.au
 Output type: au
 Output type is supported
 Input file format:
 WAVE (.wav) file, byte length: 5212,
 data format: PCM_UNSIGNED, 11025.0 Hz,
 8 bit, mono, audio data
 Bytes written: 5191
 Output file format:
 AU (.au) file, byte length: 5191,
 data format: PCM_SIGNED, 11025.0 Hz,
 8 bit, mono, audio data, frame length: 5167

Рисунок 1

Отображается информация о кодировке.

Вы увидите код, который произвел вывод на рисунке 1 позже, когда я буду обсуждать программу. Как вы можете видеть из выходных данных, код в этой программе получает и отображает информацию о кодировке (PCM_UNSIGNED, 8 бит, mono и т. д.) как во входном файле, так и в выходном файле в дополнение к типу файла. Однако эта программа не делает никаких попыток намеренно изменить кодировку. (Как я уже упоминал ранее, я начну заниматься кодированием в следующем уроке.)

Преобразование файла AU в файл WAV.

В примере, показанном на Рис. 2, входным файлом был стереофонический au-файл, созданный образцом программы из предыдущего урока. Файл au был успешно преобразован в wav-файл.

java AudioFileConvert01 junk3.au junk.wav
 Input file: junk3.au
 Output file: junk.wav
 Output type: wav
 Output type is supported
 Input file format:
 AU (.au) file, byte length: 64024,
 data format: PCM_SIGNED, 16000.0 Hz, 16 bit,
 stereo, big-endian, audio data,
 frame length: 16000
 Bytes written: 64044
 Output file format:
 WAVE (.wav) file, byte length: 64044,
 data format: PCM_SIGNED, 16000.0 Hz, 16 bit,
 stereo, little-endian, audio data

Рисунок 2

О том, что эти файлы являются стереофоническими (двухканальными) файлами, свидетельствует информация о кодировке, показанная на Рис.2.

Преобразование WAV - файла в AIF-файл.

Стандартный монофонический wav-файл Windows был успешно преобразован в aif-файл, как показано на рис. 3

java AudioFileConvert01 ringout.wav junk.aif
 Input file: ringout.wav
 Output file: junk.aif
 Output type: aif
 Output type is supported
 Input file format:
 WAVE (.wav) file, byte length: 5212,
 data format: PCM_UNSIGNED, 11025.0 Hz, 8 bit,
 mono, audio data
 Bytes written: 5221
 Output file format:
 AIFF (.aif) file, byte length: 5221,
 data format: PCM_SIGNED, 11025.0 Hz, 8 bit,
 mono, audio data, frame length: 5167

Рисунок 3

Неподдерживаемый тип выходного файла.

В примере, показанном на Рис. 4, указанный тип выходного файла, xyz, не поддерживается Java Sound API (ни какой-либо другой системой, о которой я знаю). Поэтому программа прерывается, предоставляя список типов выходных файлов, которые поддерживаются для записи системой.

java AudioFileConvert01 junk3.au junk.xyz
 Input file: junk3.au
 Output file: junk.xyz
 Output type: xyz
 Output type not supported.
 Supported audio file types: au aif wav

Рисунок 4

Обратите внимание, что реализация Java в моей системе на момент написания этой статьи поддерживает только типы файлов au, aif и wav.

Неподдерживаемый тип входного файла.

В примере, показанном на Рис. 5, входной файл, заявленный в силу своего имени и расширения, является wav-файлом. Однако это не был действительный аудиофайл. Скорее, это был просто текстовый файл, который я переименовал, чтобы заставить его выдавать себя за wav-файл. Это привело к тому, что программа выдала исключение UnsupportedAudioFileException и прервала работу.

Опять же, программа определила тип входного файла, изучив содержимое файла, а не изучив имя или расширение файла.

java AudioFileConvert01 invalidFile.wav junk.au
 Input file: invalidFile.wav
 Output file: junk.au
 Output type: au
 Output type is supported
 javax.sound.sampled.
 UnsupportedAudioFileException: could not get
 audio input stream from input stream
 at javax.sound.sampled.AudioSystem.
 getAudioInputStream(AudioSystem.java:756)
 at AudioFileConvert01.
 main(AudioFileConvert01.java:84)

Рисунок 5

Получение информации об использовании.

На рис. 6 программа была запущена без аргументов командной строки, в результате чего программа предоставила информацию об использовании и прервалась.

java AudioFileConvert01
Usage: java AudioFileConvert01
                            inputFile outputFile

Рисунок 6

Эта программа была протестирована с использованием SDK 1.4.1 под управлением WinXP

Класс с именем AudioFileConvert01.

Класс управления для программы начинается в листинге 1. Как обычно, я буду обсуждать программу фрагментарно. Вы можете просмотреть список всей программы в листинге 11 ближе к концу урока.

Программа относительно проста и состоит из метода main и следующих методов static (эти методы были объявлены статическими static, чтобы их можно было вызвать изнутри основного метода main):

  • getTargetTypesSupported - возвращает список типов аудиофайлов, которые могут быть записаны системой.
  • getTargetType - возвращает тип указанного выходного файла на основе расширения имени файла.
  • showFileType - Исследует объект File, представляющий физический аудиофайл, и отображает информацию о нем.

Метод main.

Листинг 1 содержит начало основного метода main. Код в листинге 1 проверяет количество аргументов командной строки, введенных пользователем, и отображает информацию об использовании, если пользователь не ввел никаких аргументов.

public class AudioFileConvert01{

  public static void main(String[] args){
    if(args.length != 2){
      System.out.println(
                "Usage: java AudioFileConvert01 "
                       + "inputFile outputFile");
      System.exit(0);
    }//end if

    System.out.println("Input file: " + args[0]);
    System.out.println("Output file: "+ args[1]);

Листинг 1

Кроме того, код в листинге 1 отображает имена входных и выходных файлов, предоставленные пользователем, когда эти имена файлов вводятся в качестве аргументов командной строки.

Получить и проверить тип выходного файла.

Тип выходного файла определяется расширением имени файла, предоставленным пользователем. Код в листинге 2 выделяет расширение имени файла как тип String и отображает расширение на экране.

    String outputTypeStr =
                       args[1].substring(args[1].
                           lastIndexOf(".") + 1);
    System.out.println("Output type: "
                                + outputTypeStr);

    AudioFileFormat.Type outputType =
                    getTargetType(outputTypeStr);

Листинг 2

Что еще более важно, код в листинге 2 вызывает метод getTargetType, передавая этому методу расширение имени файла в качестве параметра String.

Метод getTargetType.

Метод getTargetType проверяет, способна ли система записывать тип файла, указанный расширением. Если это так, он возвращает объект AudioFileFormat.Type, соответствующий этому расширению. Если нет, возвращается ноль.

На этом этапе я собираюсь приостановить выполнение метода main и обсудить метод с именем getTargetType.

Класс AudioFileFormat.Type.

В листинге 3 содержится весь метод с именем getTargetType.

  private static AudioFileFormat.Type
                 getTargetType(String extension){
    AudioFileFormat.Type[] typesSupported =
                 AudioSystem.getAudioFileTypes();
    //System.out.println("length: " + 
                          typesSupported.length);
    for(int i = 0; i < typesSupported.length;
                                            i++){
      if(typesSupported[i].getExtension().
                              equals(extension)){
        return typesSupported[i];
      }//конец if
    }//end for loop
    return null;//не совпадает
  }//конец getTargetType

Листинг 3

Первое, что следует отметить в отношении кода в листинге 3, это то, что метод getTargetType возвращает ссылку на объект типа AudioFileFormat.Type.

(Если вы не знакомы с обозначением точки в имени класса, это означает, что класс Type является внутренним классом класса с именем AudioFileFormat. Если вы не знакомы с внутренними классами, см. Учебные уроки по этой теме на моем веб-сайте.)

Что говорит Sun?

Вот что Sun говорит об этом классе:

"Экземпляр класса Type представляет один из стандартных типов аудиофайлов. Статические экземпляры предоставляются для общих типов."

Статические экземпляры предоставляются для следующих типов:

  • AIFC
  • AIFF
  • AU
  • SND
  • WAVE

Интересно отметить, что, хотя пять различных типов аудиофайлов определены как общие типы в этом классе, только три из этих типов в настоящее время поддерживаются для записи на моем компьютере с SDK 1.4.1 под WinXP.

Массив ссылок на объект AudioFileFormat.Type.

Код в листинге 3 вызывает метод с именем getAudioFileTypes, который является статическим методом класса AudioSystem. Этот метод возвращает список, содержащий «типы файлов, для которых система поддерживает запись файлов». Этот список хранится в массиве типа AudioFileFormat.Type.

(Листинг 3 содержит оператор с вызовом метода println, который был закомментирован. Когда этот оператор включен в моей системе, он сообщает, что длина массива равна трем, что указывает на то, что в настоящее время для записи в моей системе поддерживаются только три типа файлов. Позже вы увидите названия этих трех типов.)

Метод getExtension.

Класс AudioFileFormat.Type предоставляет метод с именем getExtension, который возвращает «общее расширение имени файла» для объекта данного типа. Код в листинге 3 использует цикл for для поиска в массиве объектов AudioFileFormat.Type в поисках совпадения с расширением имени файла, полученным в качестве входящего параметра методом getTargetType.

Если совпадение найдено, объект AudioFileFormat.Type, соответствующий этому совпадению, возвращается методом getTargetType. В противном случае метод возвращает значение null.

Testing the return value

Returning our attention to the code in the main method, the code in Listing 4 tests to determine if a null value was returned by the getTargetType method.  If not, the program displays the message:

Output type is supported

//Продолжить метод main 
    if(outputType != null){
      System.out.println(
                     "Тип вывода поддерживается");
    }else{
      System.out.println(
                   "Тип вывода не поддерживается.");
      getTargetTypesSupported();
      System.exit(0);
    }//конец else

Листинг 4

Если методом getTargetType было возвращено  значение null , программа отображает следующее сообщение, а затем вызывает метод с именем getTargetTypesSupported для отображения списка типов файлов, которые поддерживаются системой для записи.

Тип вывода не поддерживается.

Метод getTargetTypesSupported.

Цель метода с именем getTargetTypesSupported - получить и отобразить список типов файлов, поддерживаемых системой для записи.

Еще раз, я собираюсь приостановить метод main, пока буду обсуждать метод с именем getTargetTypesSupported, показанный в листинге 5.

  private static void getTargetTypesSupported(){
    AudioFileFormat.Type[] typesSupported =
                 AudioSystem.getAudioFileTypes();
    System.out.print(
                  "Supported audio file types:");
    for(int i = 0; i < typesSupported.length;
                                            i++){
      System.out.print(" " +
               typesSupported[i].getExtension());
    }//конец цикла
    System.out.println();
  }//конец getTargetTypesSupported

Листинг 5.

Получение и отображение общих расширений файлов.

Код в листинге 5 не требует особых объяснений. Этот код очень похож на код в листинге 3. Однако в листинге 5 после получения массива объектов AudioFileFormat.Type, представляющих типы файлов, поддерживаемые системой для записи, код просто получает и отображает общее расширение имени файла для каждого этих типов.

Для примера, описанного ранее (см. Рисунок 4), где я намеренно сказал программе написать неподдерживаемый тип выходного файла (xyz), код в листингах 4 и 5 выдал результат, показанный на рисунке 7.

 Output type not supported.
 Supported audio file types: au aif wav

Рисунок 7

(Обратите внимание, что список поддерживаемых типов файлов на рисунке 7 включает только три из пяти типов, идентифицированных static  экземплярами класса AudioFileFormat.type.)

Тип входного файла.

Возвращаясь еще раз к методу main, код в листинге 6 начинает работать с входным файлом.

(Обратите внимание, что определение типа входного файла не зависит от имени или расширения файла. Скорее, программа определяет тип входного файла, извлекая информацию о файле из информации, содержащейся в самом файле.)

Получить объект AudioInputStream.

Код в листинге 6 начинается с получения объекта File, представляющего входной файл.

//Продолжить метод main 
    File inputFileObj = new File(args[0]);
    AudioInputStream audioInputStream = null;
    try{
      audioInputStream = AudioSystem.
               getAudioInputStream(inputFileObj);
    }catch (Exception e){
      e.printStackTrace();
      System.exit(0);
    }//конец catch

Листинг 6

Затем код в листинге 6 использует этот объект File для получения объекта AudioInputStream, который можно использовать для чтения аудиоданных во входном файле.

Я обсуждал код, включающий объекты AudioInputStream, в нескольких предыдущих уроках. Поэтому я не буду утомлять вас, обсуждая это снова здесь.

Отображение информации о типе файла.

Код в листинге 7 вызывает метод showFileType с целью отображения информации о типе входного файла.

    System.out.println("Input file format:");
    showFileType(inputFileObj);

Листинг 7

Метод showFileType.

Еще раз, я собираюсь приостановить метод main, пока буду обсуждать метод с именем showFileType, показанный в листинге 8.

  private static void showFileType(File file){
    try{
      System.out.println(AudioSystem.
                       getAudioFileFormat(file));
    }catch(Exception e){
      e.printStackTrace();
      System.exit(0);
    }//конец catch
  }//конец showFileFormat

 Listing 8

В методе showFileType нет ничего особенного. Он просто вызывает метод с именем getAudioFileFormat, который является статическим методом класса AudioSystem, передавая объект File, который представляет входной файл в качестве параметра метода.

Метод getAudioFileFormat.

Вот что Sun говорит о методе getAudioFileFormat.

"Obtains the audio file format of the specified File. The File must point to valid audio file data."

Этот метод возвращает объект типа AudioFileFormat, ссылка на который передается в метод println для отображения.

Класс AudioFileFormat.

Вот что Sun говорит об объектах этого класса:

"Экземпляр класса AudioFileFormat описывает аудиофайл, включая тип файла, длину файла в байтах, длину в кадрах выборки аудиоданных, содержащихся в файле, и формат аудиоданных."

Как это часто бывает, этот класс имеет переопределенный метод toString, который упрощает отображение информации о содержимом объекта.

Вывод на экран для поддерживаемого типа входного файла.

На рисунке 8 показан вывод на экран, созданный листингами 7 и 8 для поддерживаемого входного аудиофайла типа WAV:

 Input file format:
 WAVE (.wav) file, byte length: 5212,
 data format: PCM_UNSIGNED, 11025.0 Hz, 8 bit,
 mono, audio data

Рисунок 8

Обратите внимание, что этот вывод содержит количество каналов и частоту дискретизации, которая не упоминается в цитате из sun в предыдущем разделе.

Вывод на экран для неподдерживаемого типа входного файла.

На рисунке 9 показан вывод на экран, созданный листингом 6, когда была сделана попытка получить объект AudioInputStream для файла, который не был допустимым аудиофайлом. (Это был текстовый файл, созданный программой Windows NotePad.)

 javax.sound.sampled.
 UnsupportedAudioFileException: could not get
 audio input stream from input stream
 at javax.sound.sampled.AudioSystem.
 getAudioInputStream(AudioSystem.java:756)
 at AudioFileConvert01.
 main(AudioFileConvert01.java:84)

Рисунок 9

В этом случае программа даже не успела вызвать метод showFileType с целью отображения информации о файле. Скорее, он генерировал исключение UnsupportedAudioFileException при попытке получить объект AudioInputStream во входном файле.

Итог по конвертации файлов.

Возвращаясь еще раз к методу main, код в листинге 9 иллюстрирует итоги преобразования аудиофайлов в Java.

(Обратите внимание, что я удалил пример из листинга 9, чтобы упростить представление. Вы можете просмотреть этот код в листинге 11 ближе к концу урока.)

//Продолжить метод main 
    int bytesWritten = 0;
    //удалить try
      bytesWritten = AudioSystem.
                        write(audioInputStream,
                              outputType,
                              new File(args[1]));
    //удалить catch
    System.out.println("Bytes written: "
                                 + bytesWritten);

Листинг 9

Метод записи класса AudioSystem.

Как оказалось, преобразование аудиофайлов с использованием Java Sound API относительно просто, если вы не пытаетесь изменить кодировку в процессе. (Как упоминалось ранее, я начну обсуждение кодировок в следующем уроке..)

(Большая часть кода в этой программе предоставлена, чтобы помочь вам понять, что происходит. Версия программы с именем AudioFileConvert02, с удаленной большей частью ненужного кода, показана в листинге 12 ближе к концу урока.)

Основы конвертации файлов

Все, что действительно необходимо для преобразования файлов с помощью Java Sound API:

  • Получить имена входных и выходных файлов.
  • Получить объект класса AudioFileFormat.Type, который определяет тип выходного файла.
  • Получить объект AudioInputStream во входном файле.
  • Вызвать метод с именем write, показанный в листинге 9, передав указанную выше информацию в качестве параметров методу write.

Это приведет к чтению входного файла и приведет к тому, что данные из входного файла будут записаны в выходной файл в указанном формате.

Метод write.

Вот что Sun говорит о методе write, использованном в листинге 9, который является статическим методом класса AudioSystem:

"Записывает поток байтов, представляющий аудиофайл указанного типа файла, в предоставленный внешний файл"

Может быть более общим.

На самом деле этот код можно было бы сделать гораздо более общим, чем в этой программе. Например, объект AudioInputStream не обязательно должен быть основан на файле. Объект AudioInputStream может быть основан на объекте TargetDataLine или на любом объекте InputStream, способном предоставлять аудиоданные в соответствии с известным AudioFormat.

Точно так же другая перегруженная версия метода write позволяет заменить объект File в третьем параметре любым объектом OutputStream, способным принимать поток аудиоданных в указанном формате.

Количество байтов, записанных в выходной файл.

Метод write возвращает количество фактически записанных байтов. Это значение отображается на экране последним оператором в листинге 9.

Информация о формате выходного файла.

Код в листинге 10 отображает информацию о формате выходного файла.

    System.out.println("Output file format:");
    showFileType(new File(args[1]));

  }//end main

Листинг 10

На рисунке 10 показан образец вывода, полученного в листинге 10 для одного из примеров, рассмотренных ранее в этом уроке:

 Output file format:
 WAVE (.wav) file, byte length: 64044,
 data format: PCM_SIGNED, 16000.0 Hz, 16 bit,
 stereo, little-endian, audio data

Рисунок 10

Запуск программы.

На этом этапе вы можете найти полезным скомпилировать и запустить программы, показанные в листингах 11 и 12, ближе к концу урока. Инструкции по эксплуатации были представлены ранее в разделе Пользовательский интерфейс.

Если вы используете медиаплеер, такой как Windows Media Player, для воспроизведения файла, обязательно удалите старый файл из медиаплеера, прежде чем пытаться создать новый файл с тем же именем и расширением. В противном случае программа не сможет создать новый файл, и произойдет ошибка времени выполнения.

Также имейте в виду, что эти программы были протестированы с использованием SDK версии 1.4.1. Поэтому я не могу быть уверен, что они будут правильно компилироваться и работать с более ранними версиями Java.

Резюме.

В этом уроке я показал вам, как конвертировать аудиоданные из одного типа аудиофайла в другой. Основные этапы такого преобразования:

  • Получить имена входных и выходных файлов.
  • Получить объект класса AudioFileFormat.Type, который определяет тип выходного файла.
  • Получить объект AudioInputStream во входном файле.
  • Вызвать метод с именем write, показанный в листинге 9, передав указанную выше информацию в качестве параметров методу write .

Я также объяснил, что эту программу можно сделать гораздо более общей, основав объект AudioInputStream на объекте InputStream, отличном от файла, или заставив выводом быть OutputStream, отличным от файла.

Вы должны иметь возможность воспроизводить выходной файл, созданный этой программой, с помощью любого стандартного медиаплеера, который может обрабатывать этот тип файла, или с помощью программы, написанной на Java, такой как программа с именем AudioPlayer02, которая была разработана на предыдущем уроке.

Что дальше?

В следующем уроке я покажу вам, как использовать кодирование и декодирование по мю-закону для сжатия и восстановления 16-битных линейных выборок PCM.

Полный список программ.

Полные списки двух программ, обсуждаемых в этом уроке, показаны в листингах 11 и 12.

/*Файл AudioFileConvert01.java
Copyright 2003, R.G.Baldwin
 
Эта программа демонстрирует возможность написания 
программы на Java для преобразования одного типа 
аудиофайла в другой тип аудиофайла.
 
Usage: java AudioFileConvert01 
                             inputFile outputFile
 
Тип выходного файла зависит от расширения имени 
выходного файла, например au, wav или aif.
 
Тип входного файла не зависит от имени или 
расширения входного файла. Фактический тип входного 
файла определяется программой независимо от имени 
или расширения.
 
Вы должны иметь возможность воспроизводить выходной 
файл с помощью любого стандартного медиаплеера, 
который может обрабатывать этот тип файла, или с 
помощью программы, написанной на Java, такой как 
программа с именем AudioPlayer02, которая 
обсуждалась на предыдущем уроке.
 
Ниже приведены примеры вывода на экран для различных 
типов файлов ввода и вывода. Обратите внимание, что 
разрывы строк были вставлены вручную, чтобы материал 
соответствовал этому узкому формату публикации.
 
В этом примере допустимый входной файл wav был 
вынужден иметь недопустимое расширение файла. 
Файл wav был успешно преобразован в файл au.
 
java AudioFileConvert01 ringout.txt junk.au
Входной файл: ringout.txt
Выходной файл: junk.au
Тип выхода: au
Тип вывода поддерживается
Формат входного файла:
WAVE (.wav) файл, длина в байтах: 5212,
формат данных: PCM_UNSIGNED, 11025.0 Hz,
8 bit, mono, audio data
Написано байтов: 5191
Формат выходного файла:
Файл AU (.au), длина байта: 5191,
формат данных: PCM_SIGNED, 11025.0 Hz,
8 бит, моно, аудиоданные, длина кадра: 5167
 
В этом примере входным файлом был стерео файл au, 
созданный программой-образцом из предыдущего урока. 
Файл au был успешно преобразован в файл wav.
 
java AudioFileConvert01 junk3.au junk.wav
Входной файл: junk3.au
Выходной файл: junk.wav
Тип выхода: wav
Тип вывода поддерживается
Формат входного файла:
Файл AU (.au), длина байта: 64024,
формат данных: PCM_SIGNED, 16000.0 Hz, 16 bit,
stereo, big-endian, audio data,
длина кадра: 16000
Написано байтов: 64044
Формат выходного файла:
WAVE (.wav) файл, длина в байтах: 64044,
формат данных: PCM_SIGNED, 16000.0 Hz, 16 bit,
stereo, little-endian, audio data
 
В этом примере входным файлом был стандартный 
WAV-файл Windows, который был успешно преобразован 
в AIF-файл.
 
java AudioFileConvert01 ringout.wav junk.aif
Входной файл: ringout.wav
Выходной файл: junk.aif
Тип выхода: aif
Тип вывода поддерживается
Формат входного файла:
WAVE (.wav) файл, длина в байтах: 5212,
формат данных: PCM_UNSIGNED, 11025.0 Hz, 8 bit,
mono, audio data
Написано байтов: 5221
Формат выходного файла:
Файл AIFF (.aif), длина в байтах: 5221,
формат данных: PCM_SIGNED, 11025.0 Hz, 8 bit,
mono, audio data, frame length: 5167
 
В этом примере для выходного файла был указан 
неподдерживаемый тип. Таким образом, программа 
была прервана, и был предоставлен список 
поддерживаемых типов выходных файлов.
 
java AudioFileConvert01 junk3.au junk.xyz
Входной файл: junk3.au
Выходной файл: junk.xyz
Тип выхода: xyz
Тип вывода не поддерживается.
Поддерживаемые типы аудиофайлов: au aif wav
 
В этом примере, несмотря на то, что входной файл был 
заявлен как WAV-файл, это не был допустимый аудиофайл. 
Скорее, это был текстовый файл, который был 
переименован, чтобы имитировать wav-файл. Это 
привело к тому, что программа выдала исключение 
времени выполнения и прервала выполнение.
 
java AudioFileConvert01 invalidFile.wav junk.au
Входной файл: invalidFile.wav
Выходной файл: junk.au
Тип выхода: au
Тип вывода поддерживается
javax.sound.sampled.
UnsupportedAudioFileException: не удалось получить
аудиовход поток из входного потока
at javax.sound.sampled.AudioSystem.
getAudioInputStream(AudioSystem.java:756)
at AudioFileConvert01.
main(AudioFileConvert01.java:84)
 
В этом примере программа была запущена 
без параметров командной строки, в результате 
чего программа предоставила информацию об 
использовании и прервалась.
 
java AudioFileConvert01
Usage: java AudioFileConvert01 
                            inputFile outputFile
 
 
Протестировано с использованием SDK 1.4.1 под WinXP
************************************************/
 
 
import java.io.*;
import javax.sound.sampled.*;
 
public class AudioFileConvert01{
 
  public static void main(String[] args){
    if(args.length != 2){
      System.out.println(
                "Usage: java AudioFileConvert01 "
                       + "inputFile outputFile");
      System.exit(0);
    }//конец if
 
    System.out.println("Input file: " + args[0]);
    System.out.println("Output file: "+ args[1]);
 
    // Тип выходного файла зависит от 
	// расширения имени выходного файла.
    String outputTypeStr =
                       args[1].substring(args[1].
                           lastIndexOf(".") + 1);
    System.out.println("Output type: "
                                + outputTypeStr);
    AudioFileFormat.Type outputType =
                    getTargetType(outputTypeStr);
    if(outputType != null){
      System.out.println(
                     "Output type is supported");
    }else{
      System.out.println(
                   "Output type not supported.");
      getTargetTypesSupported();
      System.exit(0);
    }//конец else
 
    // Обратите внимание, что тип входного файла 
	// не зависит от имени или расширения файла.
    File inputFileObj = new File(args[0]);
    AudioInputStream audioInputStream = null;
    try{
      audioInputStream = AudioSystem.
               getAudioInputStream(inputFileObj);
    }catch (Exception e){
      e.printStackTrace();
      System.exit(0);
    }//конец catch
 
    System.out.println("Input file format:");
    showFileType(inputFileObj);
 
    int bytesWritten = 0;
    try{
      bytesWritten = AudioSystem.
                        write(audioInputStream,
                              outputType,
                              new File(args[1]));
    }catch (Exception e){
      e.printStackTrace();
      System.exit(0);
    }//конец catch
    System.out.println("Bytes written: "
                                 + bytesWritten);
    System.out.println("Output file format:");
    showFileType(new File(args[1]));
 
  }//конец main
 
  private static void getTargetTypesSupported(){
    AudioFileFormat.Type[] typesSupported =
                 AudioSystem.getAudioFileTypes();
    System.out.print(
                  "Supported audio file types:");
    for(int i = 0; i < typesSupported.length;
                                            i++){
      System.out.print(" " +
               typesSupported[i].getExtension());
    }//конец цикла for
    System.out.println();
  }//end getTargetTypesSupported
 
  private static AudioFileFormat.Type
                 getTargetType(String extension){
    AudioFileFormat.Type[] typesSupported =
                 AudioSystem.getAudioFileTypes();
    for(int i = 0; i < typesSupported.length;
                                            i++){
      if(typesSupported[i].getExtension().
                              equals(extension)){
        return typesSupported[i];
      }//конец if
    }//конец цикла for
    return null;//не совпадает
  }//конец getTargetType
 
  private static void showFileType(File file){
    try{
      System.out.println(AudioSystem.
                       getAudioFileFormat(file));
    }catch(Exception e){
      e.printStackTrace();
      System.exit(0);
    }//конец catch
  }//конец showFileFormat
}//конец класса

Листинг 11

/*File AudioFileConvert02.java
Copyright 2003, R.G.Baldwin
 
Эта программа демонстрирует возможность написания 
программы на Java для преобразования одного типа 
аудиофайла в другой тип аудиофайла. Это обновленная 
версия AudioFileConvert01, в которой был удален 
весь ненужный код.
 
Usage: java AudioFileConvert02
                            inputFile outputFile
							
Тип выходного файла зависит от расширения имени 
выходного файла, например au, wav или aif.
 
Тип входного файла не зависит от имени или расширения 
входного файла. Фактический тип входного файла 
определяется программой независимо от имени или 
расширения.
 
Вы должны иметь возможность воспроизводить выходной 
файл с помощью любого стандартного медиаплеера, 
который может обрабатывать этот тип файла, или с 
помощью программы, написанной на Java, такой как 
программа с именем AudioPlayer02, которая обсуждалась 
на предыдущем уроке.
 
 
Протестировано с использованием SDK 1.4.1 под WinXP
************************************************/
 
 
import java.io.*;
import javax.sound.sampled.*;
 
public class AudioFileConvert02{
 
  public static void main(String[] args){
    if(args.length != 2){
      System.out.println(
                "Usage: java AudioFileConvert02 "
                       + "inputFile outputFile");
      System.exit(0);
    }//конец if
 
    AudioFileFormat.Type outputType =
         getTargetType(args[1].substring(args[1].
                          lastIndexOf(".") + 1));
 
    if(outputType == null){
      System.out.println(
                   "Output type not supported.");
      System.exit(0);
    }//конец else
 
    File inputFileObj = new File(args[0]);
    AudioInputStream audioInputStream = null;
    try{
      audioInputStream = AudioSystem.
               getAudioInputStream(inputFileObj);
 
      AudioSystem.write(audioInputStream,
                              outputType,
                              new File(args[1]));
    }catch (Exception e){
      e.printStackTrace();
      System.exit(0);
    }//конец catch
 
  }//конец main
  //-------------------------------------------//
 
  private static AudioFileFormat.Type
                 getTargetType(String extension){
    AudioFileFormat.Type[] typesSupported =
                 AudioSystem.getAudioFileTypes();
    for(int i = 0; i < typesSupported.length;
                                            i++){
      if(typesSupported[i].getExtension().
                              equals(extension)){
        return typesSupported[i];
      }//конец if
    }//конец цикла for
    return null;//не совпадает
  }//конец getTargetType
  //-------------------------------------------//
}//конец класса

Листинг 12

 

Предыдущая Следующая