Форум программистов, компьютерный форум CyberForum.ru

Программирование Android

Войти
Регистрация
Восстановить пароль
 
 
gvsp
13 / 2 / 0
Регистрация: 10.11.2015
Сообщений: 71
#1

Генератор звука нужной частоты - Android

07.09.2016, 01:42. Просмотров 1108. Ответов 27
Метки нет (Все метки)

Всем привет.
Что то не могу найти на просторах Интернета, как можно воспроизвести звук нужной частоты? Вариант с файлом не подходит, ибо пользователь должен подбирать частоту по его личной благозвучности. Для азбуки Морзе.
Лучшие ответы (1)
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
vxg
Модератор
3067 / 1869 / 196
Регистрация: 13.01.2012
Сообщений: 7,110
12.09.2016, 11:09     Генератор звука нужной частоты #21
gvsp, про щелчок вам уже написано
Цитата Сообщение от vxg Посмотреть сообщение
щелчок это потому что в самом конце не нулевая амплитуда. либо обрывайте когда синусоида проходит ноль либо снижайте амплитуду синусоиды до нуля перед выключением либо костылите с громкостью
заикания и прочие чудеса могут быть связаны с выделением/освобождением памяти, опять же сказано
Цитата Сообщение от vxg Посмотреть сообщение
не убивать трек, а лишь заменять/добавлять данные
gvsp
13 / 2 / 0
Регистрация: 10.11.2015
Сообщений: 71
12.09.2016, 11:38  [ТС]     Генератор звука нужной частоты #22
vxg, Если вызываю трек
Java
1
2
AudioTrack at = generateTone(1000, 100); // freqHz, durationMs
            at.play();
и не убиваю, то после двух - трёх десятков вызовов приложение вылетает. Или я при каждом вызове создаю новый трек? Тогда, как добавлять данные? Единственная идея зациклить generateTone в потоке и проверять, когда нужно что то воспроизвести:
Java
1
2
3
4
if (dot == 1){
// воспроизвести точку}
else if (dash == 1){
// воспроизвести тире}
Но подозреваю, что без убийства трека оно тоже повиснет через сколько то вызовов.
vxg
Модератор
3067 / 1869 / 196
Регистрация: 13.01.2012
Сообщений: 7,110
12.09.2016, 11:56     Генератор звука нужной частоты #23
gvsp, один раз создайте трек, а потом просто пишите в него данные
Java
1
track.write(samples, 0, count);
Добавлено через 1 минуту
gvsp, вообще если вам нужно только точки тире делать - запишите их в студии, поместите в SoundPool и проигрывайте оттуда программно
gvsp
13 / 2 / 0
Регистрация: 10.11.2015
Сообщений: 71
12.09.2016, 16:20  [ТС]     Генератор звука нужной частоты #24
vxg, Спасибо попробую. К сожалению использовать готовые файлы не очень удобно, нужно иметь возможность регулировать в неких пределах частоту и длительность. Конечно, если не получится с генератором, то придётся задать фиксированные выборы из нескольких файлов. Но есть куча приложений для морзянки с выбором частоы и длительности и с идеальным звучанием. Например (не знаю можно ли тут давать ссылки, если что просьба не банить) Morse app К сожалению нет ни одного хорошего приложения именно для обучения, поэтому решил написать сам, благо ничего сложного то там нет.

Добавлено через 4 часа 15 минут
vxg, извините, что надоедаю. Примерно так?
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Создадим такой же генератор, как сейчас:
// Генератор звука
    private AudioTrack generateTone(double freqHz, int durationMs)
    {
        int sampleRate = 48000;z
        int count = (int)( sampleRate * 2.0 * (durationMs / 1000.0)) & ~1;
        short[] samples = new short[count];
        for(int i = 0; i < count; i += 2){
            short sample = (short)(Math.sin(2 * Math.PI * i / (sampleRate / freqHz)) * 0x7FFF);
            samples[i + 0] = sample;
        }
        AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
                AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT,
                count * (Short.SIZE / 8), AudioTrack.MODE_STATIC);
        track.write(samples, 0, count);
        return track;
    }
 
// Вызовем его сразу же, с нулевой частотой и длительностью, чтоб не загудел:
AudioTrack at = generateTone(0, 0); // freqHz, durationMs
            at.play();
 
 
// Данные samples и count просчитываем заранее:
 int sampleRate = 48000;
        int count = (int)( sampleRate * 2.0 * (durationMs / 1000.0)) & ~1;
        short[] samples = new short[count];
        for(int i = 0; i < count; i += 2){
            short sample = (short)(Math.sin(2 * Math.PI * i / (sampleRate / freqHz)) * 0x7FFF);
            samples[i + 0] = sample;
 
// И пишем данные вызывая звук, например по кнопке:
public void onClickTestSound(View view) {
track.write(samples, 0, count);
    }
 
// При выходе из активности убиваем, ибо практика показывает, что сам не умирает
try {
            track.pause();
        } catch (IllegalStateException e) {
        }
        track.flush();
        track.release();
        track = null;
vxg
Модератор
3067 / 1869 / 196
Регистрация: 13.01.2012
Сообщений: 7,110
12.09.2016, 18:38     Генератор звука нужной частоты #25
gvsp, что мешает попробовать)? Думаю да, хотя ваш код несколько загадочен. Я бы просто создал трек и кормил его данными
gvsp
13 / 2 / 0
Регистрация: 10.11.2015
Сообщений: 71
12.09.2016, 20:23  [ТС]     Генератор звука нужной частоты #26
vxg, // И пишем данные вызывая звук, например по кнопке:
Java
1
2
3
public void onClickTestSound(View view) {
track.write(samples, 0, count);
    }
Вылетает. Как же правильно накормить?
Пробовал и сразу же считать:
Java
1
2
3
4
5
6
7
8
9
public void onClickTestSound(View view) {
int sampleRate = 48000;
        int count = (int)( sampleRate * 2.0 * (durationMs / 1000.0)) & ~1;
        short[] samples = new short[count];
        for(int i = 0; i < count; i += 2){
            short sample = (short)(Math.sin(2 * Math.PI * i / (sampleRate / freqHz)) * 0x7FFF);
            samples[i + 0] = sample;
track.write(samples, 0, count);
    }
И вызывать ещё раз генератор:
Java
1
2
3
4
5
6
7
8
9
10
11
public void onClickTestSound(View view) {
int sampleRate = 48000;
        int count = (int)( sampleRate * 2.0 * (durationMs / 1000.0)) & ~1;
        short[] samples = new short[count];
        for(int i = 0; i < count; i += 2){
            short sample = (short)(Math.sin(2 * Math.PI * i / (sampleRate / freqHz)) * 0x7FFF);
            samples[i + 0] = sample;
AudioTrack at = generateTone(freqHz, durationMs ); // freqHz, durationMs freq, durationDot
            at.play();
track.write(samples, 0, count);
    }
В последнем случае пищит, но тоже вылетает.
vxg
Модератор
3067 / 1869 / 196
Регистрация: 13.01.2012
Сообщений: 7,110
13.09.2016, 09:40     Генератор звука нужной частоты #27
gvsp
у меня так
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//где то создается трек
AudioTrack at = new AudioTrack(...);
 
//сразу после создания мы можем начать класть туда данные
at.write(buffer, 0, length);
 
//а можем и не начать. рано или поздно вне зависимости от наличия данных в треке мы вызовем play
at.play();
 
//после этого мы продолжаем класть данные при этом не забывая что если мы перекормим трек данными он может не принять очередную порцию - поэтому выдумаем свою функцию play
private static void play(AudioTrack at, byte[] buffer, int length) {
    int offset = 0;
    while (true) {
        offset += at.write(buffer, offset, length - offset);
        if (offset == length) break;
        if (Thread.currentThread().isInterrupted()) break;
    }
}
 
//и будем ее использовать (только не в UI потоке)
play(buffer, length);
 
//когда это все нам надоест - отпустим трек на волю
if (at != null) {
    try {
        at.pause();
    } catch (IllegalStateException e) {
    }
    at.flush();
    at.release();
    at = null;
}
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
01.10.2016, 10:07     Генератор звука нужной частоты
Еще ссылки по теме:

Android Получение частоты ЦП
Генератор / сборник иконок Android
Android Прочитать данные из нужной БД
Генератор звукового сигнала Android
Запись звука unity Android

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
gvsp
13 / 2 / 0
Регистрация: 10.11.2015
Сообщений: 71
01.10.2016, 10:07  [ТС]     Генератор звука нужной частоты #28
В итоге без заиканий короткие звуки удалось получить только с записью в файл wav и выводом их через Soundpool.
От щелчков избавился добавив атаку и релиз.
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
    int sampleRate = 44100; // стандартная частота дискретизации для wav файла
    int Attack = 200;  // Атака. Сглаживание переднего фронта
    int Release = 500;  // Релиз. Сглаживание заднего фронта
    durationDot = 60 // длительность звука в мс
// вычисляем переменные
        int countDot = (int)( sampleRate * 2.0 * (durationDot / 1000.0)) &~1;
        int totalDataLen = countDot + 36;
        long byteRate = 16 * sampleRate / 8;
        FileDot = new byte[44 + countDot];
// генерируем заголовок wav файла
        FileDot[0] = 'R'; // 'RIFF'
        FileDot[1] = 'I';
        FileDot[2] = 'F';
        FileDot[3] = 'F';
        FileDot[4] = (byte) (totalDataLen & 0xff); // totalDataLen  размер файла
        FileDot[5] = (byte) ((totalDataLen >> 8) & 0xff);
        FileDot[6] = (byte) ((totalDataLen >> 16) & 0xff);
        FileDot[7] = (byte) ((totalDataLen >> 24) & 0xff);
        FileDot[8] = 'W';
        FileDot[9] = 'A';
        FileDot[10] = 'V';
        FileDot[11] = 'E';
        FileDot[12] = 'f'; // 'fmt' - chunk
        FileDot[13] = 'm';
        FileDot[14] = 't';
        FileDot[15] = ' ';
        FileDot[16] = 16; // 16 для формата PCM
        FileDot[17] = 0;
        FileDot[18] = 0;
        FileDot[19] = 0;
        FileDot[20] = 1; //Для PCM = 1
        FileDot[21] = 0;
        FileDot[22] = 1; // Количество каналов. Моно = 1
        FileDot[23] = 0;
        FileDot[24] = (byte) (sampleRate & 0xff); // longSampleRate частота дискретизаии (44100)
        FileDot[26] = (byte) ((sampleRate >> 16) & 0xff);FileDot[25] = (byte) ((sampleRate >> 8) & 0xff);
        FileDot[27] = (byte) ((sampleRate >> 24) & 0xff);
        FileDot[28] = (byte) (byteRate & 0xff); // byteRate битрейт
        FileDot[29] = (byte) ((byteRate >> 8) & 0xff);
        FileDot[30] = (byte) ((byteRate >> 16) & 0xff);
        FileDot[31] = (byte) ((byteRate >> 24) & 0xff);
        FileDot[32] = (byte) (1 * 16 / 8); // block align
        FileDot[33] = 0;
        FileDot[34] = 16; // бит в сэмпле (16)
        FileDot[35] = 0;
        FileDot[36] = 'd';
        FileDot[37] = 'a';
        FileDot[38] = 't';
        FileDot[39] = 'a';
        FileDot[40] = (byte) (countDot & 0xff);
        FileDot[41] = (byte) ((countDot >> 8) & 0xff);
        FileDot[42] = (byte) ((countDot >> 16) & 0xff);
        FileDot[43] = (byte) ((countDot >> 24) & 0xff);
// генерируем тело wav файла
      //  начало с плавным возрастанием амплитуды
        for(int i = 0; i < countDot; i += 2){
            if (i < Attack) { // Атака плавное возрастание звука
                short sample = (short) ((Math.sin(Math.PI * i / (sampleRate / Frequence)) * 0x7FFF)  *  i / Attack);
                FileDot[44+i] = (byte) (sample & 0xff);
                FileDot[44+i+1] = (byte) ((sample >> 8) & 0xff);
            }
           //  конец с плавным затуханием амплитуды
            else if (i > (countDot-Release)) { // Релиз затухание звука
                short sample = (short) ((Math.sin(Math.PI * i /
                        (sampleRate / Frequence)) * 0x7FFF) * (countDot-i)/ Release);
                FileDot[44+i] = (byte) (sample & 0xff);
                FileDot[44+i+1] = (byte) ((sample >> 8) & 0xff);
            }
           // середина синусоиды без изменений
            else { 
                short sample = (short)(Math.sin(Math.PI * i /
                        (sampleRate / Frequence)) * 0x7FFF);
                FileDot[44+i] = (byte) (sample & 0xff);
                FileDot[44+i+1] = (byte) ((sample >> 8) & 0xff);
            }
        }
 
        // записываем в файл
        String FileDotName = "Dot.wav"; // имя файла
        FileOutputStream fos = null;
        try {
            fos = openFileOutput(FileDotName, Context.MODE_PRIVATE);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        try {
            fos.write(FileDot);
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
Yandex
Объявления
01.10.2016, 10:07     Генератор звука нужной частоты
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru