Spec-Zone .ru
спецификации, руководства, описания, API
Содержание документации

<Содержание

Глава 7: Используя Файлы и Преобразователи Формата

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

Как был кратко упомянут в Главе 3, "Получая доступ к Ресурсам Аудиосистемы," API Звука Java предоставляет разработчикам приложений различные средства для ввода/вывода файла и преобразований формата. Прикладные программы могут читать, записать, и преобразовать между множеством форматов звукового файла и форматами аудиоданных.

Глава 2, "Краткий обзор Выбранного Пакета," представлял основные классы, связанные с форматами аудиоданных и звуковыми файлами. Как анализ:

Отметьте, что реализация API Звука Java не обязательно предоставляет всесторонние средства для того, чтобы они считали, писали, и преобразовали аудио в различных данных и форматах файлов. Это могло бы поддерживать только наиболее распространенные данные и форматы файлов. Однако, поставщики услуг могут разработать и распределить службы преобразования, которые расширяют этот набор, как обрисовано в общих чертах в Главе 14, "Предоставляя Услуги Выбранного аудио." AudioSystem класс предоставляет методы, которые позволяют прикладным программам изучать, какие преобразования доступны, как описано позже в этой главе при "Преобразовании Форматов файлов и Форматов данных."

Чтение Звуковых файлов

AudioSystem класс обеспечивает два типа читающих файл служб:

Первый из них дается тремя разновидностями getAudioFileFormat метод:

static AudioFileFormat getAudioFileFormat (java.io.File file)
static AudioFileFormat getAudioFileFormat(java.io.InputStream stream)
static AudioFileFormat getAudioFileFormat (java.net.URL url)

Как упомянуто выше, возвращенный AudioFileFormat объект говорит Вам тип файла, длину данных в файле, кодировании, порядке байтов, числе каналов, уровня выборки, и числа битов на выборку.

Второй тип читающей файл функциональности дается ими AudioSystem методы

static AudioInputStream getAudioInputStream (java.io.File file)
static AudioInputStream getAudioInputStream (java.net.URL url)
static AudioInputStream getAudioInputStream (java.io.InputStream stream)

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

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

  1. Доберитесь AudioInputStream объект от файла.
  2. Создайте байтовый массив, в котором Вы сохраните последовательные блоки данных от файла.
  3. Неоднократно читайте байты из потока звукового входа в массив. На каждой итерации сделайте что-то полезное с байтами в массиве (например, Вы могли бы играть их, фильтровать их, проанализировать их, вывести на экран их, или записать им в другой файл).

Следующий пример кода обрисовывает в общих чертах эти шаги.
int totalFramesRead = 0;
File fileIn = new File(somePathName);
// somePathName is a pre-existing string whose value was
// based on a user selection.
try {
  AudioInputStream audioInputStream = 
    AudioSystem.getAudioInputStream(fileIn);
  int bytesPerFrame = 
    audioInputStream.getFormat().getFrameSize();
  // Set an arbitrary buffer size of 1024 frames.
  int numBytes = 1024 * bytesPerFrame; 
  byte[] audioBytes = new byte[numBytes];
  try {
    int numBytesRead = 0;
    int numFramesRead = 0;
    // Try to read numBytes bytes from the file.
    while ((numBytesRead = 
      audioInputStream.read(audioBytes)) != -1) {
      // Calculate the number of frames actually read.
      numFramesRead = numBytesRead / bytesPerFrame;
      totalFramesRead += numFramesRead;
      // Here, do something useful with the audio data that's 
      // now in the audioBytes array...
    }
  } catch (Exception ex) { 
    // Handle the error...
  }
} catch (Exception e) {
  // Handle the error...
}
Давайте смотреть на то, что происходит в вышеупомянутом примере кода. Во-первых, внешний пункт попытки инстанцирует AudioInputStream объект посредством звонка AudioSystem.getAudioInputStream(File) метод. Этот метод прозрачно выполняет все тестирование, требуемое определить, является ли указанный файл фактически звуковым файлом типа, который поддерживается API Звука Java. Если осматриваемый файл (fileIn в этом примере), не звуковой файл, или звуковой файл некоторого неподдерживаемого типа, UnsupportedAudioFileException исключение выдается. Это поведение удобно в этом, прикладной программист не должен быть обеспокоен тестированием атрибутов файла, ни соблюдением никаких соглашений о присвоении имен файла. Вместо этого getAudioInputStream метод заботится обо всем низкоуровневом парсинге и проверке, которая обязана проверять входного файла.

Внешнее try пункт тогда создает байтовый массив, audioBytes, из произвольной фиксированной длины. Мы удостоверяемся, что его длина в байтах равняется целому числу фреймов, так, чтобы мы не закончили тем, что читали только часть фрейма или, еще хуже, только часть выборки. Этот байтовый массив будет служить буфером, чтобы временно содержать блок аудиоданных, поскольку это читается из потока. Если бы мы знали, что будем читать только очень короткие звуковые файлы, то мы могли бы сделать этот массив той же самой длиной как данные в файле, получая длину в байтах от длины во фреймах, как возвращено AudioInputStream's getFrameLength метод. (Фактически, мы, вероятно, только использовали бы a Clip объект вместо этого.), Но избегать исчерпывать память в общем случае, мы вместо этого читаем файл в блоках, один буфер за один раз.

Внутреннее try пункт содержит a while цикл, который является, где мы читаем аудиоданные из AudioInputStream в байтовый массив. Следует добавить, что код в этом цикле, чтобы обработать аудиоданные в этом массиве любым способом является подходящим для потребностей Вашей программы. Если Вы примените некоторую обработку сигнала к данным, то Вы должны будете, вероятно, запросить AudioInputStream's AudioFormat далее, чтобы изучить число битов на выборку и так далее.

Отметьте что метод AudioInputStream.read(byte[]) возвращает число чтения байтов — не число выборок или фреймов. Этот метод возвращается-1, когда нет больше данных, чтобы читать. После обнаружения этого условия мы повреждаемся от while цикл.

Запись Звуковых файлов

Предыдущий раздел, описанный основы чтения звукового файла, используя определенные методы AudioSystem и AudioInputStream классы. Этот раздел описывает, как выписать аудиоданные к новому файлу.

Следующий AudioSystem метод создает дисковый файл указанного типа файла. Файл будет содержать аудиоданные, это находится в указанном AudioInputStream:

static int write(AudioInputStream in, 
  AudioFileFormat.Type fileType, File out)
Отметьте, что вторым параметром должны быть одни из типов файлов, поддерживаемых системой (например, AU, AIFF, или WAV), иначе write метод бросит IllegalArgumentException. Чтобы избежать этого, можно протестировать действительно ли деталь AudioInputStream может быть записан определенному типу файла, вызывая это AudioSystem метод:
static boolean isFileTypeSupported
  (AudioFileFormat.Type fileType, AudioInputStream stream)
который возвратится true только если определенная комбинация поддерживается.

Более широко можно изучить, какие типы файла система может записать, вызывая один из них AudioSystem методы:

static AudioFileFormat.Type[] getAudioFileTypes() 
static AudioFileFormat.Type[]  
  getAudioFileTypes(AudioInputStream stream) 
Первый из этих возвратов все типы файла, который система может записать, и вторые возвраты только те, которых система может записать из данного потока звукового входа.

Следующая выборка демонстрирует один метод для того, чтобы создать выходной файл из AudioInputStream использование write метод упоминается выше.

File fileOut = new File(someNewPathName);
AudioFileFormat.Type fileType = fileFormat.getType();
if (AudioSystem.isFileTypeSupported(fileType, 
    audioInputStream)) {
  AudioSystem.write(audioInputStream, fileType, fileOut);
}
Первый оператор выше, создает новое File объект, fileOut, с пользователем - или определенный программой путь. Второй оператор получает тип файла от существования ранее AudioFileFormat объект вызывают fileFormat, который, возможно, был получен из другого звукового файла, такого как тот, который был считан в "разделе" Звуковых файлов Чтения этой главы. (Вы могли вместо этого предоставить любой поддерживаемый тип файла, который Вы хотите, вместо того, чтобы получить тип файла откуда-либо. Например, Вы могли бы удалить второй оператор и заменить другие два возникновения fileType в коде выше с AudioFileFormat.Type.WAVE.)

Третий оператор тестирует, может ли файл определяемого типа быть записан из требуемого AudioInputStream. Как формат файла, этот поток, возможно, был получен из звукового файла ранее чтение. (Если так, по-видимому Вы обработали или изменили его данные в некотором роде, потому что иначе есть более легкие способы просто скопировать файл.) Или возможно поток содержит байты, которые были недавно получены от ввода микрофона.

Наконец, поток, тип файла, и выходной файл передают к AudioSystem.write метод, чтобы выполнить цель записи файла.

Преобразование Форматов файлов и Форматов данных

Вспомните из раздела, "Каковы Отформатированные Аудиоданные?" в Главе 2, "Краткий обзор Выбранного Пакета," это API Звука Java различает форматы аудиофайла и форматы аудиоданных. Эти два более или менее независимы. Примерно говоря, формат данных обращается к пути, которым компьютер представляет каждый, необработанные данные указывают (выборка), в то время как формат файла обращается к организации звукового файла как сохраненный на диске. У каждого формата звукового файла есть определенная структура, которая определяет, например, информацию, хранившую в заголовке файла. В некоторых случаях формат файла также включает структуры, которые содержат некоторую форму метаданных, в дополнение к фактическим "необработанным" аудиосэмплам. Остаток от этой главы исследует методы API Звука Java, которые включают множеству преобразования формата данных и формат файла.

Преобразование от Одного Формата файла до Другого

Эти покрытия раздела основные принципы преобразования аудиофайла вводят API Звука Java. Еще раз мы излагаем гипотетическую программу, цель которой, на сей раз, состоит в том, чтобы считать аудиоданные из произвольного входного файла и записать это в файл, тип которого является AIFF. Конечно, входной файл должен иметь тип, что система способна к чтению, и выходной файл должен иметь тип, что система способна к записи. (В этом примере мы предполагаем, что система способна к записи файлов AIFF.) Пример программы не делает никакого преобразования формата данных. Если входной формат данных файла не может быть представлен как файл AIFF, программа просто уведомляет пользователя той проблемы. С другой стороны, если входной звуковой файл уже файл AIFF, программа уведомляет пользователя, что нет никакой потребности преобразовать это.

Следующая функция реализует логику, только описанную:

public void ConvertFileToAIFF(String inputPath, 
  String outputPath) {
  AudioFileFormat inFileFormat;
  File inFile;
  File outFile;
  try {
    inFile = new File(inputPath);
    outFile = new File(outputPath);     
  } catch (NullPointerException ex) {
    System.out.println("Error: one of the 
      ConvertFileToAIFF" +" parameters is null!");
    return;
  }
  try {
    // query file type
    inFileFormat = AudioSystem.getAudioFileFormat(inFile);
    if (inFileFormat.getType() != AudioFileFormat.Type.AIFF) 
    {
      // inFile is not AIFF, so let's try to convert it.
      AudioInputStream inFileAIS = 
        AudioSystem.getAudioInputStream(inFile);
      inFileAIS.reset(); // rewind
      if (AudioSystem.isFileTypeSupported(
             AudioFileFormat.Type.AIFF, inFileAIS)) {
         // inFileAIS can be converted to AIFF. 
         // so write the AudioInputStream to the
         // output file.
         AudioSystem.write(inFileAIS,
           AudioFileFormat.Type.AIFF, outFile);
         System.out.println("Successfully made AIFF file, "
           + outFile.getPath() + ", from "
           + inFileFormat.getType() + " file, " +
           inFile.getPath() + ".");
         inFileAIS.close();
         return; // All done now
       } else
         System.out.println("Warning: AIFF conversion of " 
           + inFile.getPath()
           + " is not currently supported by AudioSystem.");
    } else
      System.out.println("Input file " + inFile.getPath() +
          " is AIFF." + " Conversion is unnecessary.");
  } catch (UnsupportedAudioFileException e) {
    System.out.println("Error: " + inFile.getPath()
        + " is not a supported audio file type!");
    return;
  } catch (IOException e) {
    System.out.println("Error: failure attempting to read " 
      + inFile.getPath() + "!");
    return;
  }
}

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

Большая часть этой функции является очевидной и не является определенной для API Звука Java. Есть, однако, несколько методов API Звука Java, используемых подпрограммой, которые крайне важны для звуковых преобразований типа файла. Эти вызовы метода все находятся во втором try пункт, выше, и включает следующее:

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

Преобразование Аудио между Различными Форматами данных

Предыдущий раздел показал, как использовать API Звука Java, чтобы преобразовать файл из одного формата файла (то есть, один тип звукового файла) другому. Этот раздел исследует некоторые из методов, которые включают преобразованиям формата аудиоданных.

В предыдущем разделе мы читаем данные из файла произвольного типа, и сохранили это в файле AIFF. Отметьте, что, хотя мы изменили тип файла, используемого, чтобы хранить данные, мы не изменяли формат аудиоданных непосредственно. (Наиболее распространенные типы аудиофайла, включая AIFF, могут содержать аудиоданные различных форматов.), Так если исходный файл содержавшие аудиоданные качества CD (16-разрядный объем выборки, демонстрационный уровень на 44.1 кГц, и два канала), так был бы наш выходной файл AIFF.

Теперь предположите, что мы хотим определить формат данных выходного файла, так же как тип файла. Например, возможно мы сохранили много длинных файлов для использования в Интернете, и обеспокоены количеством дискового пространства и загружаем время, требуемое нашими файлами. Мы могли бы хотеть создавать меньшие файлы AIFF, которые содержат данные например более низкого разрешения, данные, у которых есть 8-разрядный объем выборки, демонстрационный уровень на 8 кГц, и единственный канал.

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

Основной метод для преобразования аудиоданных, еще раз, находится в AudioSystem класс. Этот метод является разновидностью getAudioInputStream:

AudioInputStream getAudioInputStream(AudioFormat
    format, AudioInputStream stream)
Эта функция возвращается AudioInputStream это - результат преобразования AudioInputStream, stream, использование обозначенного AudioFormat, format. Если преобразование не поддерживается AudioSystem, эта функция бросает IllegalArgumentException.

Избегать, чтобы, мы могли сначала проверить, может ли система выполнить необходимое преобразование, вызывая это AudioSystem метод:

boolean isConversionSupported(AudioFormat targetFormat,
    AudioFormat sourceFormat)
В этом случае мы передали бы stream.getFormat() как второй параметр.

Создать определенное AudioFormat объект, мы используем один из двух AudioFormat конструкторы, показанные ниже, также

 AudioFormat(float sampleRate, int sampleSizeInBits,
    int channels, boolean signed, boolean bigEndian)
который создает AudioFormat с линейным кодированием PCM и данными параметрами, или
AudioFormat(AudioFormat.Encoding encoding, 
    float sampleRate, int sampleSizeInBits, int channels,
    int frameSize, float frameRate, boolean bigEndian) 
который также создает AudioFormat, но позволяет Вам определять кодирование, тип телосложения, и частоту кадров, в дополнение к другим параметрам.

Теперь, вооруженный методами выше, давайте видеть, как мы могли бы расширить наш ConvertFileToAIFF функция, чтобы выполнить требуемые "низкие-res" аудиоданные форматирует преобразование. Во-первых, мы создали бы AudioFormat объект, описывающий требуемый выходной формат аудиоданных. Следующий оператор был бы достаточен и мог быть вставлен около вершины функции:

AudioFormat outDataFormat = new AudioFormat((float) 8000.0,
(int) 8, (int) 1, true, false);
Начиная с AudioFormat конструктор выше описывает формат с 8-разрядными выборками, последний параметр конструктору, который определяет, с обратным порядком байтов ли выборки или с прямым порядком байтов, не важен. (Большой против прямого порядка байтов только проблема, если объем выборки больше чем единственный байт.)

Следующий пример показывает, как мы использовали бы это новое AudioFormat преобразовать AudioInputStream, inFileAIS, то, что мы создали из входного файла:

AudioInputStream lowResAIS;         
  if (AudioSystem.isConversionSupported(outDataFormat,   
    inFileAIS.getFormat())) {
    lowResAIS = AudioSystem.getAudioInputStream
      (outDataFormat, inFileAIS);
  }
Не имело бы значения слишком много, где мы вставили этот код, пока это было после конструкции inFileAIS. Без isConversionSupported тест, вызов привел бы к сбою и бросил бы IllegalArgumentException если определенное преобразование, которое требуют, неподдерживалось. (В этом случае управление передало бы соответствующему catch пункт в нашей функции.)

Так этой точкой в процессе, мы произвели бы новое AudioInputStream, следуя из преобразования исходного входного файла (в AudioInputStream форма) к требуемым аудиоданным с низкой разрешающей способностью форматируют как определено outDataFormat.

Заключительный шаг, чтобы произвести требуемый звуковой файл AIFF с низкой разрешающей способностью должен был бы заменить AudioInputStream параметр в звонке AudioSystem.write (то есть, первый параметр) с нашим преобразованным потоком, lowResAIS, следующим образом:

AudioSystem.write(lowResAIS, AudioFileFormat.Type.AIFF, 
  outFile);
Эти немного модификаций к нашему более раннему функциональному продукту что-то, что преобразовывает и аудиоданные и формат файла любого указанного входного файла, предполагая, конечно, что система поддерживает преобразование.

Изучение, Какие Преобразования Доступны

Несколько AudioSystem методы тестируют свои параметры, чтобы определить, поддерживает ли система определенное преобразование формата данных или пишущую файл работу. (Как правило, каждый метод соединяется с другим, который выполняет преобразование данных или пишет файл.) Один из этих методов запроса, AudioSystem.isFileTypeSupported, использовался в нашей функции в качестве примера, ConvertFileToAIFF, определить, была ли система способна к записи аудиоданных к файлу AIFF. Связанное AudioSystem метод, getAudioFileTypes(AudioInputStream), возвращает полный список поддерживаемых типов файлов для данного потока, как массив AudioFileFormat.Type экземпляры. Метод:

boolean isConversionSupported(AudioFormat.Encoding encoding, 
AudioFormat format)
используется, чтобы определить, может ли поток звукового входа указанного кодирования быть получен из потока звукового входа, у которого есть указанный аудиоформат. Точно так же метод:
boolean isConversionSupported(AudioFormat newFormat,
                              AudioFormat oldFormat) 

говорит нам ли AudioInputStream с указанным аудиоформатом, newFormat, может быть получен через преобразование AudioInputStream у этого есть аудиоформат oldFormat. (Этот метод был вызван в выборке кода предыдущего раздела, которая создала поток звукового входа с низкой разрешающей способностью, lowResAIS.)

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

 


Oracle и/или его филиалы Авторское право © 1993, 2011, Oracle и/или его филиалы. Все права защищены.
Свяжитесь с Нами