parent
a920dbdb9a
commit
b7a4e30cf6
@ -0,0 +1 @@
|
||||
# 这是一个src
|
||||
@ -0,0 +1,69 @@
|
||||
# Details
|
||||
|
||||
Date : 2025-06-10 08:55:17
|
||||
|
||||
Directory e:\\pycharm_projects\\AudioClassification-Pytorch-master
|
||||
|
||||
Total : 54 files, 6851 codes, 838 comments, 1201 blanks, all 8890 lines
|
||||
|
||||
[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
|
||||
## Files
|
||||
| filename | language | code | comment | blank | total |
|
||||
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||
| [README.md](/README.md) | Markdown | 302 | 0 | 72 | 374 |
|
||||
| [README\_en.md](/README_en.md) | Markdown | 231 | 0 | 45 | 276 |
|
||||
| [audio-classification-platform/README.md](/audio-classification-platform/README.md) | Markdown | 96 | 0 | 41 | 137 |
|
||||
| [audio-classification-platform/backend/app.py](/audio-classification-platform/backend/app.py) | Python | 255 | 35 | 61 | 351 |
|
||||
| [audio-classification-platform/backend/config.py](/audio-classification-platform/backend/config.py) | Python | 22 | 8 | 10 | 40 |
|
||||
| [audio-classification-platform/backend/requirements.txt](/audio-classification-platform/backend/requirements.txt) | pip requirements | 7 | 0 | 1 | 8 |
|
||||
| [audio-classification-platform/frontend/index.html](/audio-classification-platform/frontend/index.html) | HTML | 25 | 0 | 2 | 27 |
|
||||
| [audio-classification-platform/frontend/package.json](/audio-classification-platform/frontend/package.json) | JSON | 24 | 0 | 1 | 25 |
|
||||
| [audio-classification-platform/frontend/src/App.vue](/audio-classification-platform/frontend/src/App.vue) | Vue | 88 | 5 | 14 | 107 |
|
||||
| [audio-classification-platform/frontend/src/components/AudioRecorder.vue](/audio-classification-platform/frontend/src/components/AudioRecorder.vue) | Vue | 551 | 38 | 102 | 691 |
|
||||
| [audio-classification-platform/frontend/src/components/AudioRecorder\_new.vue](/audio-classification-platform/frontend/src/components/AudioRecorder_new.vue) | Vue | 811 | 48 | 162 | 1,021 |
|
||||
| [audio-classification-platform/frontend/src/components/AudioUpload.vue](/audio-classification-platform/frontend/src/components/AudioUpload.vue) | Vue | 580 | 28 | 107 | 715 |
|
||||
| [audio-classification-platform/frontend/src/components/HistoryList.vue](/audio-classification-platform/frontend/src/components/HistoryList.vue) | Vue | 513 | 25 | 79 | 617 |
|
||||
| [audio-classification-platform/frontend/src/components/PredictionResult.vue](/audio-classification-platform/frontend/src/components/PredictionResult.vue) | Vue | 803 | 22 | 117 | 942 |
|
||||
| [audio-classification-platform/frontend/src/main.js](/audio-classification-platform/frontend/src/main.js) | JavaScript | 13 | 1 | 5 | 19 |
|
||||
| [audio-classification-platform/frontend/src/router/index.js](/audio-classification-platform/frontend/src/router/index.js) | JavaScript | 14 | 0 | 4 | 18 |
|
||||
| [audio-classification-platform/frontend/src/utils/api.js](/audio-classification-platform/frontend/src/utils/api.js) | JavaScript | 156 | 25 | 33 | 214 |
|
||||
| [audio-classification-platform/frontend/src/views/HomePage.vue](/audio-classification-platform/frontend/src/views/HomePage.vue) | Vue | 692 | 40 | 110 | 842 |
|
||||
| [audio-classification-platform/frontend/vite.config.js](/audio-classification-platform/frontend/vite.config.js) | JavaScript | 32 | 0 | 2 | 34 |
|
||||
| [audio-classification-platform/start.bat](/audio-classification-platform/start.bat) | Batch | 20 | 0 | 5 | 25 |
|
||||
| [audio-classification-platform/start.sh](/audio-classification-platform/start.sh) | Shell Script | 26 | 3 | 8 | 37 |
|
||||
| [configs/augmentation.yml](/configs/augmentation.yml) | YAML | 21 | 21 | 5 | 47 |
|
||||
| [configs/cam++.yml](/configs/cam++.yml) | YAML | 43 | 33 | 5 | 81 |
|
||||
| [configs/ecapa\_tdnn.yml](/configs/ecapa_tdnn.yml) | YAML | 43 | 33 | 5 | 81 |
|
||||
| [configs/eres2net.yml](/configs/eres2net.yml) | YAML | 43 | 33 | 5 | 81 |
|
||||
| [configs/panns.yml](/configs/panns.yml) | YAML | 43 | 33 | 5 | 81 |
|
||||
| [configs/res2net.yml](/configs/res2net.yml) | YAML | 43 | 33 | 5 | 81 |
|
||||
| [configs/resnet\_se.yml](/configs/resnet_se.yml) | YAML | 43 | 33 | 5 | 81 |
|
||||
| [configs/tdnn.yml](/configs/tdnn.yml) | YAML | 43 | 33 | 5 | 81 |
|
||||
| [create\_data.py](/create_data.py) | Python | 75 | 9 | 16 | 100 |
|
||||
| [eval.py](/eval.py) | Python | 20 | 2 | 5 | 27 |
|
||||
| [extract\_features.py](/extract_features.py) | Python | 13 | 2 | 5 | 20 |
|
||||
| [infer.py](/infer.py) | Python | 17 | 1 | 6 | 24 |
|
||||
| [infer\_record.py](/infer_record.py) | Python | 40 | 7 | 12 | 59 |
|
||||
| [macls/\_\_init\_\_.py](/macls/__init__.py) | Python | 1 | 0 | 1 | 2 |
|
||||
| [macls/data\_utils/\_\_init\_\_.py](/macls/data_utils/__init__.py) | Python | 0 | 0 | 1 | 1 |
|
||||
| [macls/data\_utils/collate\_fn.py](/macls/data_utils/collate_fn.py) | Python | 17 | 4 | 3 | 24 |
|
||||
| [macls/data\_utils/featurizer.py](/macls/data_utils/featurizer.py) | Python | 88 | 36 | 9 | 133 |
|
||||
| [macls/data\_utils/reader.py](/macls/data_utils/reader.py) | Python | 114 | 33 | 11 | 158 |
|
||||
| [macls/metric/\_\_init\_\_.py](/macls/metric/__init__.py) | Python | 0 | 0 | 1 | 1 |
|
||||
| [macls/metric/metrics.py](/macls/metric/metrics.py) | Python | 9 | 1 | 3 | 13 |
|
||||
| [macls/optimizer/\_\_init\_\_.py](/macls/optimizer/__init__.py) | Python | 26 | 0 | 7 | 33 |
|
||||
| [macls/optimizer/scheduler.py](/macls/optimizer/scheduler.py) | Python | 42 | 0 | 7 | 49 |
|
||||
| [macls/predict.py](/macls/predict.py) | Python | 124 | 47 | 7 | 178 |
|
||||
| [macls/trainer.py](/macls/trainer.py) | Python | 338 | 99 | 20 | 457 |
|
||||
| [macls/utils/\_\_init\_\_.py](/macls/utils/__init__.py) | Python | 0 | 0 | 1 | 1 |
|
||||
| [macls/utils/checkpoint.py](/macls/utils/checkpoint.py) | Python | 113 | 40 | 10 | 163 |
|
||||
| [macls/utils/record.py](/macls/utils/record.py) | Python | 18 | 8 | 6 | 32 |
|
||||
| [macls/utils/utils.py](/macls/utils/utils.py) | Python | 99 | 16 | 17 | 132 |
|
||||
| [record\_audio.py](/record_audio.py) | Python | 10 | 0 | 5 | 15 |
|
||||
| [requirements.txt](/requirements.txt) | pip requirements | 17 | 0 | 1 | 18 |
|
||||
| [setup.py](/setup.py) | Python | 43 | 1 | 11 | 55 |
|
||||
| [tools/download\_language\_data.sh](/tools/download_language_data.sh) | Shell Script | 19 | 1 | 10 | 30 |
|
||||
| [train.py](/train.py) | Python | 25 | 1 | 5 | 31 |
|
||||
|
||||
[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
@ -0,0 +1,15 @@
|
||||
# Diff Details
|
||||
|
||||
Date : 2025-06-10 08:55:17
|
||||
|
||||
Directory e:\\pycharm_projects\\AudioClassification-Pytorch-master
|
||||
|
||||
Total : 0 files, 0 codes, 0 comments, 0 blanks, all 0 lines
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||
|
||||
## Files
|
||||
| filename | language | code | comment | blank | total |
|
||||
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||
|
@ -0,0 +1,19 @@
|
||||
# Diff Summary
|
||||
|
||||
Date : 2025-06-10 08:55:17
|
||||
|
||||
Directory e:\\pycharm_projects\\AudioClassification-Pytorch-master
|
||||
|
||||
Total : 0 files, 0 codes, 0 comments, 0 blanks, all 0 lines
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||
|
||||
## Languages
|
||||
| language | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
|
||||
## Directories
|
||||
| path | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
|
||||
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||
@ -0,0 +1,22 @@
|
||||
Date : 2025-06-10 08:55:17
|
||||
Directory : e:\pycharm_projects\AudioClassification-Pytorch-master
|
||||
Total : 0 files, 0 codes, 0 comments, 0 blanks, all 0 lines
|
||||
|
||||
Languages
|
||||
+----------+------------+------------+------------+------------+------------+
|
||||
| language | files | code | comment | blank | total |
|
||||
+----------+------------+------------+------------+------------+------------+
|
||||
+----------+------------+------------+------------+------------+------------+
|
||||
|
||||
Directories
|
||||
+------+------------+------------+------------+------------+------------+
|
||||
| path | files | code | comment | blank | total |
|
||||
+------+------------+------------+------------+------------+------------+
|
||||
+------+------------+------------+------------+------------+------------+
|
||||
|
||||
Files
|
||||
+----------+----------+------------+------------+------------+------------+
|
||||
| filename | language | code | comment | blank | total |
|
||||
+----------+----------+------------+------------+------------+------------+
|
||||
| Total | | 0 | 0 | 0 | 0 |
|
||||
+----------+----------+------------+------------+------------+------------+
|
||||
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,50 @@
|
||||
# Summary
|
||||
|
||||
Date : 2025-06-10 08:55:17
|
||||
|
||||
Directory e:\\pycharm_projects\\AudioClassification-Pytorch-master
|
||||
|
||||
Total : 54 files, 6851 codes, 838 comments, 1201 blanks, all 8890 lines
|
||||
|
||||
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
|
||||
## Languages
|
||||
| language | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| Vue | 7 | 4,038 | 206 | 691 | 4,935 |
|
||||
| Python | 25 | 1,509 | 350 | 240 | 2,099 |
|
||||
| Markdown | 3 | 629 | 0 | 158 | 787 |
|
||||
| YAML | 8 | 322 | 252 | 40 | 614 |
|
||||
| JavaScript | 4 | 215 | 26 | 44 | 285 |
|
||||
| Shell Script | 2 | 45 | 4 | 18 | 67 |
|
||||
| HTML | 1 | 25 | 0 | 2 | 27 |
|
||||
| pip requirements | 2 | 24 | 0 | 2 | 26 |
|
||||
| JSON | 1 | 24 | 0 | 1 | 25 |
|
||||
| Batch | 1 | 20 | 0 | 5 | 25 |
|
||||
|
||||
## Directories
|
||||
| path | files | code | comment | blank | total |
|
||||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||
| . | 54 | 6,851 | 838 | 1,201 | 8,890 |
|
||||
| . (Files) | 11 | 793 | 23 | 183 | 999 |
|
||||
| audio-classification-platform | 19 | 4,728 | 278 | 864 | 5,870 |
|
||||
| audio-classification-platform (Files) | 3 | 142 | 3 | 54 | 199 |
|
||||
| audio-classification-platform\\backend | 3 | 284 | 43 | 72 | 399 |
|
||||
| audio-classification-platform\\frontend | 13 | 4,302 | 232 | 738 | 5,272 |
|
||||
| audio-classification-platform\\frontend (Files) | 3 | 81 | 0 | 5 | 86 |
|
||||
| audio-classification-platform\\frontend\\src | 10 | 4,221 | 232 | 733 | 5,186 |
|
||||
| audio-classification-platform\\frontend\\src (Files) | 2 | 101 | 6 | 19 | 126 |
|
||||
| audio-classification-platform\\frontend\\src\\components | 5 | 3,258 | 161 | 567 | 3,986 |
|
||||
| audio-classification-platform\\frontend\\src\\router | 1 | 14 | 0 | 4 | 18 |
|
||||
| audio-classification-platform\\frontend\\src\\utils | 1 | 156 | 25 | 33 | 214 |
|
||||
| audio-classification-platform\\frontend\\src\\views | 1 | 692 | 40 | 110 | 842 |
|
||||
| configs | 8 | 322 | 252 | 40 | 614 |
|
||||
| macls | 15 | 989 | 284 | 104 | 1,377 |
|
||||
| macls (Files) | 3 | 463 | 146 | 28 | 637 |
|
||||
| macls\\data_utils | 4 | 219 | 73 | 24 | 316 |
|
||||
| macls\\metric | 2 | 9 | 1 | 4 | 14 |
|
||||
| macls\\optimizer | 2 | 68 | 0 | 14 | 82 |
|
||||
| macls\\utils | 4 | 230 | 64 | 34 | 328 |
|
||||
| tools | 1 | 19 | 1 | 10 | 30 |
|
||||
|
||||
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||
@ -0,0 +1,107 @@
|
||||
Date : 2025-06-10 08:55:17
|
||||
Directory : e:\pycharm_projects\AudioClassification-Pytorch-master
|
||||
Total : 54 files, 6851 codes, 838 comments, 1201 blanks, all 8890 lines
|
||||
|
||||
Languages
|
||||
+------------------+------------+------------+------------+------------+------------+
|
||||
| language | files | code | comment | blank | total |
|
||||
+------------------+------------+------------+------------+------------+------------+
|
||||
| Vue | 7 | 4,038 | 206 | 691 | 4,935 |
|
||||
| Python | 25 | 1,509 | 350 | 240 | 2,099 |
|
||||
| Markdown | 3 | 629 | 0 | 158 | 787 |
|
||||
| YAML | 8 | 322 | 252 | 40 | 614 |
|
||||
| JavaScript | 4 | 215 | 26 | 44 | 285 |
|
||||
| Shell Script | 2 | 45 | 4 | 18 | 67 |
|
||||
| HTML | 1 | 25 | 0 | 2 | 27 |
|
||||
| pip requirements | 2 | 24 | 0 | 2 | 26 |
|
||||
| JSON | 1 | 24 | 0 | 1 | 25 |
|
||||
| Batch | 1 | 20 | 0 | 5 | 25 |
|
||||
+------------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Directories
|
||||
+------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| path | files | code | comment | blank | total |
|
||||
+------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
| . | 54 | 6,851 | 838 | 1,201 | 8,890 |
|
||||
| . (Files) | 11 | 793 | 23 | 183 | 999 |
|
||||
| audio-classification-platform | 19 | 4,728 | 278 | 864 | 5,870 |
|
||||
| audio-classification-platform (Files) | 3 | 142 | 3 | 54 | 199 |
|
||||
| audio-classification-platform\backend | 3 | 284 | 43 | 72 | 399 |
|
||||
| audio-classification-platform\frontend | 13 | 4,302 | 232 | 738 | 5,272 |
|
||||
| audio-classification-platform\frontend (Files) | 3 | 81 | 0 | 5 | 86 |
|
||||
| audio-classification-platform\frontend\src | 10 | 4,221 | 232 | 733 | 5,186 |
|
||||
| audio-classification-platform\frontend\src (Files) | 2 | 101 | 6 | 19 | 126 |
|
||||
| audio-classification-platform\frontend\src\components | 5 | 3,258 | 161 | 567 | 3,986 |
|
||||
| audio-classification-platform\frontend\src\router | 1 | 14 | 0 | 4 | 18 |
|
||||
| audio-classification-platform\frontend\src\utils | 1 | 156 | 25 | 33 | 214 |
|
||||
| audio-classification-platform\frontend\src\views | 1 | 692 | 40 | 110 | 842 |
|
||||
| configs | 8 | 322 | 252 | 40 | 614 |
|
||||
| macls | 15 | 989 | 284 | 104 | 1,377 |
|
||||
| macls (Files) | 3 | 463 | 146 | 28 | 637 |
|
||||
| macls\data_utils | 4 | 219 | 73 | 24 | 316 |
|
||||
| macls\metric | 2 | 9 | 1 | 4 | 14 |
|
||||
| macls\optimizer | 2 | 68 | 0 | 14 | 82 |
|
||||
| macls\utils | 4 | 230 | 64 | 34 | 328 |
|
||||
| tools | 1 | 19 | 1 | 10 | 30 |
|
||||
+------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||
|
||||
Files
|
||||
+------------------------------------------------------------------------------------------------------------------------------------+------------------+------------+------------+------------+------------+
|
||||
| filename | language | code | comment | blank | total |
|
||||
+------------------------------------------------------------------------------------------------------------------------------------+------------------+------------+------------+------------+------------+
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\README.md | Markdown | 302 | 0 | 72 | 374 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\README_en.md | Markdown | 231 | 0 | 45 | 276 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\README.md | Markdown | 96 | 0 | 41 | 137 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\backend\app.py | Python | 255 | 35 | 61 | 351 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\backend\config.py | Python | 22 | 8 | 10 | 40 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\backend\requirements.txt | pip requirements | 7 | 0 | 1 | 8 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\index.html | HTML | 25 | 0 | 2 | 27 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\package.json | JSON | 24 | 0 | 1 | 25 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\App.vue | Vue | 88 | 5 | 14 | 107 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\AudioRecorder.vue | Vue | 551 | 38 | 102 | 691 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\AudioRecorder_new.vue | Vue | 811 | 48 | 162 | 1,021 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\AudioUpload.vue | Vue | 580 | 28 | 107 | 715 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\HistoryList.vue | Vue | 513 | 25 | 79 | 617 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\PredictionResult.vue | Vue | 803 | 22 | 117 | 942 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\main.js | JavaScript | 13 | 1 | 5 | 19 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\router\index.js | JavaScript | 14 | 0 | 4 | 18 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\utils\api.js | JavaScript | 156 | 25 | 33 | 214 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\views\HomePage.vue | Vue | 692 | 40 | 110 | 842 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\vite.config.js | JavaScript | 32 | 0 | 2 | 34 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\start.bat | Batch | 20 | 0 | 5 | 25 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\start.sh | Shell Script | 26 | 3 | 8 | 37 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\augmentation.yml | YAML | 21 | 21 | 5 | 47 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\cam++.yml | YAML | 43 | 33 | 5 | 81 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\ecapa_tdnn.yml | YAML | 43 | 33 | 5 | 81 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\eres2net.yml | YAML | 43 | 33 | 5 | 81 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\panns.yml | YAML | 43 | 33 | 5 | 81 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\res2net.yml | YAML | 43 | 33 | 5 | 81 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\resnet_se.yml | YAML | 43 | 33 | 5 | 81 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\tdnn.yml | YAML | 43 | 33 | 5 | 81 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\create_data.py | Python | 75 | 9 | 16 | 100 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\eval.py | Python | 20 | 2 | 5 | 27 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\extract_features.py | Python | 13 | 2 | 5 | 20 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\infer.py | Python | 17 | 1 | 6 | 24 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\infer_record.py | Python | 40 | 7 | 12 | 59 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\__init__.py | Python | 1 | 0 | 1 | 2 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\__init__.py | Python | 0 | 0 | 1 | 1 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\collate_fn.py | Python | 17 | 4 | 3 | 24 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\featurizer.py | Python | 88 | 36 | 9 | 133 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\reader.py | Python | 114 | 33 | 11 | 158 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\metric\__init__.py | Python | 0 | 0 | 1 | 1 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\metric\metrics.py | Python | 9 | 1 | 3 | 13 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\optimizer\__init__.py | Python | 26 | 0 | 7 | 33 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\optimizer\scheduler.py | Python | 42 | 0 | 7 | 49 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\predict.py | Python | 124 | 47 | 7 | 178 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\trainer.py | Python | 338 | 99 | 20 | 457 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\__init__.py | Python | 0 | 0 | 1 | 1 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\checkpoint.py | Python | 113 | 40 | 10 | 163 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\record.py | Python | 18 | 8 | 6 | 32 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\utils.py | Python | 99 | 16 | 17 | 132 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\record_audio.py | Python | 10 | 0 | 5 | 15 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\requirements.txt | pip requirements | 17 | 0 | 1 | 18 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\setup.py | Python | 43 | 1 | 11 | 55 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\tools\download_language_data.sh | Shell Script | 19 | 1 | 10 | 30 |
|
||||
| e:\pycharm_projects\AudioClassification-Pytorch-master\train.py | Python | 25 | 1 | 5 | 31 |
|
||||
| Total | | 6,851 | 838 | 1,201 | 8,890 |
|
||||
+------------------------------------------------------------------------------------------------------------------------------------+------------------+------------+------------+------------+------------+
|
||||
@ -0,0 +1,296 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
macls.egg-info/
|
||||
|
||||
# PyInstaller
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django/Flask stuff
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
Pipfile.lock
|
||||
|
||||
# PEP 582
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# Node.js dependencies
|
||||
node_modules/
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
package-lock.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage/
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
.env.local
|
||||
.env.production
|
||||
|
||||
# parcel-bundler cache
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
|
||||
# Gatsby files
|
||||
# Comment in the public line in if your project uses Gatsby
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# Audio Classification specific ignores
|
||||
# Model files (usually large)
|
||||
*.pth
|
||||
*.pt
|
||||
*.h5
|
||||
*.ckpt
|
||||
*.pb
|
||||
*.onnx
|
||||
*.pkl
|
||||
*.joblib
|
||||
|
||||
# Dataset directories (usually large audio files)
|
||||
dataset/
|
||||
dataset/*/audio/
|
||||
dataset/*/wav/
|
||||
dataset/*/mp3/
|
||||
dataset/*/flac/
|
||||
# Uncomment if you want to ignore all audio files
|
||||
# *.wav
|
||||
# *.mp3
|
||||
# *.flac
|
||||
# *.ogg
|
||||
# *.m4a
|
||||
# *.aac
|
||||
|
||||
# Training artifacts and logs
|
||||
log/
|
||||
logs/
|
||||
output/
|
||||
outputs/
|
||||
uploads/
|
||||
results/
|
||||
checkpoints/
|
||||
models/
|
||||
pretrained_models/
|
||||
feature_models/
|
||||
runs/
|
||||
wandb/
|
||||
mlruns/
|
||||
.mlflow/
|
||||
|
||||
# Temporary files
|
||||
temp/
|
||||
tmp/
|
||||
*.tmp
|
||||
test*.py
|
||||
|
||||
# OS generated files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
# IDE files
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# Audio processing temporary files
|
||||
*.spec
|
||||
*.mfcc
|
||||
*.mel
|
||||
|
||||
# Frontend build files
|
||||
audio-classification-platform/frontend/dist/
|
||||
audio-classification-platform/frontend/build/
|
||||
audio-classification-platform/frontend/.vite/
|
||||
|
||||
# Uploaded files directory
|
||||
audio-classification-platform/backend/uploads/
|
||||
|
||||
# Local development configuration
|
||||
audio-classification-platform/backend/.env
|
||||
audio-classification-platform/frontend/.env.local
|
||||
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@ -0,0 +1,39 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
# 配置
|
||||
class Config:
|
||||
# 模型配置
|
||||
MODEL_CONFIG_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../configs/cam++.yml'))
|
||||
MODEL_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../models/CAMPPlus_Fbank/best_model/'))
|
||||
LABEL_FILE_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../dataset/label_list.txt'))
|
||||
|
||||
# Flask配置
|
||||
SECRET_KEY = 'your-secret-key-here'
|
||||
MAX_CONTENT_LENGTH = 50 * 1024 * 1024 # 50MB
|
||||
|
||||
# 文件上传配置
|
||||
UPLOAD_FOLDER = 'uploads'
|
||||
ALLOWED_EXTENSIONS = {'wav', 'mp3', 'flac', 'm4a', 'ogg', 'aac'}
|
||||
|
||||
# 音频处理配置
|
||||
TARGET_SAMPLE_RATE = 16000
|
||||
|
||||
# 日志配置
|
||||
LOG_LEVEL = 'INFO'
|
||||
|
||||
# GPU配置
|
||||
USE_GPU = True
|
||||
|
||||
class DevelopmentConfig(Config):
|
||||
DEBUG = True
|
||||
|
||||
class ProductionConfig(Config):
|
||||
DEBUG = False
|
||||
|
||||
# 根据环境变量选择配置
|
||||
config = {
|
||||
'development': DevelopmentConfig,
|
||||
'production': ProductionConfig,
|
||||
'default': DevelopmentConfig
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
Flask==2.3.3
|
||||
Flask-CORS==4.0.0
|
||||
librosa==0.10.1
|
||||
soundfile==0.12.1
|
||||
numpy==1.24.3
|
||||
loguru==0.7.2
|
||||
Werkzeug==2.3.7
|
||||
@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>声纹识别系统</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Microsoft YaHei', sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "audio-classification-frontend",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"serve": "vite preview"
|
||||
}, "dependencies": {
|
||||
"vue": "^3.3.4",
|
||||
"vue-router": "^4.2.4",
|
||||
"axios": "^1.5.0",
|
||||
"element-plus": "^2.3.9",
|
||||
"@element-plus/icons-vue": "^2.1.0",
|
||||
"echarts": "^5.4.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.3.4",
|
||||
"vite": "^4.4.9",
|
||||
"unplugin-vue-components": "^0.25.2",
|
||||
"unplugin-auto-import": "^0.16.6"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// 主应用组件
|
||||
</script>
|
||||
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#app {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
|
||||
font-family: 'Inter', 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
|
||||
color: #333;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* 全局美化样式 */
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* 自定义滚动条 */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
/* 全局动画 */
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInLeft {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
#app {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,690 @@
|
||||
<template>
|
||||
<div class="audio-recorder">
|
||||
<div class="recorder-content">
|
||||
<!-- 录音状态显示 -->
|
||||
<div class="recorder-status">
|
||||
<div class="status-indicator" :class="{
|
||||
active: isRecording,
|
||||
ready: isReady,
|
||||
processing: isProcessing
|
||||
}">
|
||||
<div class="status-bg"></div>
|
||||
<transition name="icon-switch" mode="out-in">
|
||||
<el-icon class="status-icon processing" v-if="isProcessing" key="processing">
|
||||
<Loading />
|
||||
</el-icon>
|
||||
<el-icon class="status-icon recording" v-else-if="isRecording" key="recording">
|
||||
<Microphone />
|
||||
</el-icon>
|
||||
<el-icon class="status-icon ready" v-else-if="isReady" key="ready">
|
||||
<Microphone />
|
||||
</el-icon>
|
||||
<el-icon class="status-icon default" v-else key="default">
|
||||
<MicrophoneOne />
|
||||
</el-icon>
|
||||
</transition>
|
||||
|
||||
<!-- 录音波纹效果 -->
|
||||
<div v-if="isRecording" class="recording-waves">
|
||||
<div class="wave wave-1"></div>
|
||||
<div class="wave wave-2"></div>
|
||||
<div class="wave wave-3"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="status-text">
|
||||
<h3 class="status-title">{{ statusTitle }}</h3>
|
||||
<p class="primary-text">{{ statusText }}</p>
|
||||
<transition name="slide-down">
|
||||
<p class="secondary-text" v-if="recordingTime > 0">
|
||||
<el-icon><Timer /></el-icon>
|
||||
录音时长: {{ formatTime(recordingTime) }}
|
||||
</p>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 录音控制按钮 -->
|
||||
<div class="recorder-controls">
|
||||
<transition name="button-switch" mode="out-in">
|
||||
<el-button
|
||||
v-if="!isRecording && !isProcessing"
|
||||
type="primary"
|
||||
size="large"
|
||||
:disabled="disabled || !isReady"
|
||||
@click="startRecording"
|
||||
class="record-button"
|
||||
key="start"
|
||||
>
|
||||
<template #icon>
|
||||
<el-icon><Microphone /></el-icon>
|
||||
</template>
|
||||
<span>开始录音</span>
|
||||
<div class="button-glow"></div>
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
v-else-if="isRecording"
|
||||
type="danger"
|
||||
size="large"
|
||||
@click="stopRecording"
|
||||
class="stop-button"
|
||||
key="stop"
|
||||
>
|
||||
<template #icon>
|
||||
<el-icon><VideoPause /></el-icon>
|
||||
</template>
|
||||
<span>停止录音</span>
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
v-else
|
||||
size="large"
|
||||
loading
|
||||
class="processing-button"
|
||||
key="processing"
|
||||
>
|
||||
<span>正在处理...</span>
|
||||
</el-button>
|
||||
</transition>
|
||||
</div>
|
||||
|
||||
<!-- 录音设置 -->
|
||||
<div class="recorder-settings">
|
||||
<div class="settings-header">
|
||||
<el-icon><Setting /></el-icon>
|
||||
<span>录音设置</span>
|
||||
</div>
|
||||
<el-form :model="settings" label-width="80px" size="small" class="settings-form">
|
||||
<el-form-item label="录音时长">
|
||||
<el-select v-model="settings.duration" :disabled="isRecording" class="duration-select">
|
||||
<el-option label="3秒" :value="3">
|
||||
<div class="option-content">
|
||||
<span>3秒</span>
|
||||
<el-tag size="small" type="info">快速</el-tag>
|
||||
</div>
|
||||
</el-option>
|
||||
<el-option label="5秒" :value="5">
|
||||
<div class="option-content">
|
||||
<span>5秒</span>
|
||||
<el-tag size="small" type="success">推荐</el-tag>
|
||||
</div>
|
||||
</el-option>
|
||||
<el-option label="10秒" :value="10">
|
||||
<div class="option-content">
|
||||
<span>10秒</span>
|
||||
<el-tag size="small" type="warning">详细</el-tag>
|
||||
</div>
|
||||
</el-option>
|
||||
<el-option label="15秒" :value="15" />
|
||||
<el-option label="30秒" :value="30" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="自动停止">
|
||||
<el-switch
|
||||
v-model="settings.autoStop"
|
||||
:disabled="isRecording"
|
||||
active-color="#52c41a"
|
||||
inactive-color="rgba(255, 255, 255, 0.3)"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 音频可视化 -->
|
||||
<transition name="fade">
|
||||
<div v-if="isRecording" class="audio-visualizer">
|
||||
<div class="visualizer-header">
|
||||
<el-icon><DataAnalysis /></el-icon>
|
||||
<span>实时音频波形</span>
|
||||
</div>
|
||||
<canvas ref="canvasRef" class="visualizer-canvas"></canvas>
|
||||
<div class="visualizer-info">
|
||||
<div class="info-item">
|
||||
<span class="label">音量:</span>
|
||||
<div class="volume-bar">
|
||||
<div class="volume-fill" :style="{ width: `${volume}%` }"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<!-- 录音预览 -->
|
||||
<transition name="slide-up">
|
||||
<div v-if="recordedAudio" class="audio-preview">
|
||||
<div class="preview-header">
|
||||
<div class="preview-title">
|
||||
<el-icon class="preview-icon"><Headphone /></el-icon>
|
||||
<span>录音预览</span>
|
||||
</div>
|
||||
<div class="preview-actions">
|
||||
<el-button type="text" size="small" @click="playRecording" class="action-button">
|
||||
<el-icon><VideoPlay /></el-icon>
|
||||
播放
|
||||
</el-button>
|
||||
<el-button type="text" size="small" @click="clearRecording" class="action-button danger">
|
||||
<el-icon><Delete /></el-icon>
|
||||
删除
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="audio-player-container">
|
||||
<audio
|
||||
ref="audioPlayerRef"
|
||||
controls
|
||||
:src="recordedAudio.url"
|
||||
class="audio-player"
|
||||
>
|
||||
您的浏览器不支持音频播放
|
||||
</audio>
|
||||
</div>
|
||||
<div class="preview-info">
|
||||
<div class="info-item">
|
||||
<el-icon><Timer /></el-icon>
|
||||
<span>时长: {{ formatTime(recordedAudio.duration) }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<el-icon><DataBoard /></el-icon>
|
||||
<span>大小: {{ formatFileSize(recordedAudio.size) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="submitRecording"
|
||||
:loading="isSubmitting"
|
||||
class="submit-button"
|
||||
>
|
||||
识别录音
|
||||
</el-button>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { apiService } from '../utils/api'
|
||||
|
||||
// Props
|
||||
const props = defineProps({
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
// Emits
|
||||
const emit = defineEmits(['record-success', 'record-error'])
|
||||
|
||||
// 响应式数据
|
||||
const isRecording = ref(false)
|
||||
const isReady = ref(false)
|
||||
const isSubmitting = ref(false)
|
||||
const isProcessing = ref(false)
|
||||
const recordingTime = ref(0)
|
||||
const recordedAudio = ref(null)
|
||||
const canvasRef = ref()
|
||||
const audioPlayerRef = ref()
|
||||
const volume = ref(0)
|
||||
|
||||
// 录音相关变量
|
||||
let mediaRecorder = null
|
||||
let audioChunks = []
|
||||
let recordingTimer = null
|
||||
let audioContext = null
|
||||
let analyser = null
|
||||
let microphone = null
|
||||
let animationId = null
|
||||
|
||||
// 录音设置
|
||||
const settings = ref({
|
||||
duration: 5, // 默认5秒
|
||||
autoStop: true
|
||||
})
|
||||
|
||||
// 计算属性
|
||||
const statusTitle = computed(() => {
|
||||
if (isProcessing.value) return '处理中'
|
||||
if (isRecording.value) return '录音中'
|
||||
if (isReady.value) return '就绪'
|
||||
return '准备中'
|
||||
})
|
||||
|
||||
const statusText = computed(() => {
|
||||
if (isProcessing.value) return '正在处理录音数据...'
|
||||
if (!isReady.value) return '正在初始化麦克风...'
|
||||
if (isRecording.value) return '正在录音中,请对着麦克风说话'
|
||||
return '点击开始录音按钮进行音频识别'
|
||||
})
|
||||
|
||||
// 初始化录音
|
||||
const initRecorder = async () => {
|
||||
try {
|
||||
const stream = await navigator.mediaDevices.getUserMedia({
|
||||
audio: {
|
||||
sampleRate: 16000,
|
||||
channelCount: 1,
|
||||
echoCancellation: true,
|
||||
noiseSuppression: true
|
||||
}
|
||||
})
|
||||
|
||||
// 创建MediaRecorder
|
||||
mediaRecorder = new MediaRecorder(stream, {
|
||||
mimeType: 'audio/webm;codecs=opus'
|
||||
})
|
||||
|
||||
// 设置音频上下文用于可视化
|
||||
audioContext = new (window.AudioContext || window.webkitAudioContext)()
|
||||
analyser = audioContext.createAnalyser()
|
||||
microphone = audioContext.createMediaStreamSource(stream)
|
||||
microphone.connect(analyser)
|
||||
|
||||
analyser.fftSize = 256
|
||||
|
||||
// 事件监听
|
||||
mediaRecorder.ondataavailable = (event) => {
|
||||
if (event.data.size > 0) {
|
||||
audioChunks.push(event.data)
|
||||
}
|
||||
}
|
||||
|
||||
mediaRecorder.onstop = () => {
|
||||
const audioBlob = new Blob(audioChunks, { type: 'audio/webm' })
|
||||
createAudioPreview(audioBlob)
|
||||
audioChunks = []
|
||||
}
|
||||
|
||||
isReady.value = true
|
||||
ElMessage.success('麦克风初始化成功')
|
||||
|
||||
} catch (error) {
|
||||
console.error('麦克风初始化失败:', error)
|
||||
ElMessage.error('无法访问麦克风,请检查权限设置')
|
||||
}
|
||||
}
|
||||
|
||||
// 开始录音
|
||||
const startRecording = () => {
|
||||
if (!mediaRecorder || mediaRecorder.state !== 'inactive') return
|
||||
|
||||
audioChunks = []
|
||||
recordingTime.value = 0
|
||||
isRecording.value = true
|
||||
|
||||
mediaRecorder.start()
|
||||
|
||||
// 开始计时
|
||||
recordingTimer = setInterval(() => {
|
||||
recordingTime.value++
|
||||
|
||||
// 自动停止
|
||||
if (settings.value.autoStop && recordingTime.value >= settings.value.duration) {
|
||||
stopRecording()
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
// 开始音频可视化
|
||||
startVisualization()
|
||||
|
||||
ElMessage.info('开始录音')
|
||||
}
|
||||
|
||||
// 停止录音
|
||||
const stopRecording = () => {
|
||||
if (!mediaRecorder || mediaRecorder.state !== 'recording') return
|
||||
|
||||
isRecording.value = false
|
||||
mediaRecorder.stop()
|
||||
|
||||
// 清除计时器
|
||||
if (recordingTimer) {
|
||||
clearInterval(recordingTimer)
|
||||
recordingTimer = null
|
||||
}
|
||||
|
||||
// 停止可视化
|
||||
stopVisualization()
|
||||
|
||||
ElMessage.success('录音完成')
|
||||
}
|
||||
|
||||
// 创建音频预览
|
||||
const createAudioPreview = (audioBlob) => {
|
||||
const url = URL.createObjectURL(audioBlob)
|
||||
recordedAudio.value = {
|
||||
blob: audioBlob,
|
||||
url: url,
|
||||
duration: recordingTime.value,
|
||||
size: audioBlob.size
|
||||
}
|
||||
}
|
||||
|
||||
// 播放录音
|
||||
const playRecording = () => {
|
||||
if (audioPlayerRef.value) {
|
||||
audioPlayerRef.value.play()
|
||||
}
|
||||
}
|
||||
|
||||
// 清除录音
|
||||
const clearRecording = () => {
|
||||
if (recordedAudio.value) {
|
||||
URL.revokeObjectURL(recordedAudio.value.url)
|
||||
recordedAudio.value = null
|
||||
}
|
||||
recordingTime.value = 0
|
||||
}
|
||||
|
||||
// 提交录音进行识别
|
||||
const submitRecording = async () => {
|
||||
if (!recordedAudio.value) return
|
||||
|
||||
isSubmitting.value = true
|
||||
|
||||
try {
|
||||
// 使用Web Audio API解码音频数据
|
||||
const arrayBuffer = await recordedAudio.value.blob.arrayBuffer()
|
||||
|
||||
// 创建临时音频上下文用于解码
|
||||
const tempAudioContext = new (window.AudioContext || window.webkitAudioContext)()
|
||||
const audioBuffer = await tempAudioContext.decodeAudioData(arrayBuffer)
|
||||
|
||||
// 获取第一个声道的音频数据
|
||||
const channelData = audioBuffer.getChannelData(0)
|
||||
const audioData = Array.from(channelData)
|
||||
|
||||
// 关闭临时音频上下文
|
||||
await tempAudioContext.close()
|
||||
|
||||
const response = await apiService.predictAudioData({
|
||||
audio_data: audioData,
|
||||
sample_rate: audioBuffer.sampleRate
|
||||
})
|
||||
|
||||
if (response.data.status === 'success') {
|
||||
emit('record-success', response.data.result)
|
||||
clearRecording()
|
||||
} else {
|
||||
throw new Error(response.data.message)
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
emit('record-error', error.message)
|
||||
} finally {
|
||||
isSubmitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 开始音频可视化
|
||||
const startVisualization = () => {
|
||||
if (!canvasRef.value || !analyser) return
|
||||
|
||||
const canvas = canvasRef.value
|
||||
const ctx = canvas.getContext('2d')
|
||||
const bufferLength = analyser.frequencyBinCount
|
||||
const dataArray = new Uint8Array(bufferLength)
|
||||
|
||||
const draw = () => {
|
||||
if (!isRecording.value) return
|
||||
|
||||
animationId = requestAnimationFrame(draw)
|
||||
|
||||
analyser.getByteFrequencyData(dataArray)
|
||||
|
||||
ctx.fillStyle = 'rgb(255, 255, 255)'
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height)
|
||||
|
||||
const barWidth = (canvas.width / bufferLength) * 2.5
|
||||
let barHeight
|
||||
let x = 0
|
||||
|
||||
for (let i = 0; i < bufferLength; i++) {
|
||||
barHeight = dataArray[i] / 255 * canvas.height
|
||||
|
||||
ctx.fillStyle = `rgb(${barHeight + 100}, 102, 234)`
|
||||
ctx.fillRect(x, canvas.height - barHeight, barWidth, barHeight)
|
||||
|
||||
x += barWidth + 1
|
||||
}
|
||||
}
|
||||
|
||||
draw()
|
||||
}
|
||||
|
||||
// 停止音频可视化
|
||||
const stopVisualization = () => {
|
||||
if (animationId) {
|
||||
cancelAnimationFrame(animationId)
|
||||
animationId = null
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化时间
|
||||
const formatTime = (seconds) => {
|
||||
const mins = Math.floor(seconds / 60)
|
||||
const secs = seconds % 60
|
||||
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
|
||||
}
|
||||
|
||||
// 格式化文件大小
|
||||
const formatFileSize = (bytes) => {
|
||||
if (bytes === 0) return '0 B'
|
||||
|
||||
const k = 1024
|
||||
const sizes = ['B', 'KB', 'MB', 'GB']
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
||||
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
|
||||
}
|
||||
|
||||
// 组件挂载
|
||||
onMounted(() => {
|
||||
initRecorder()
|
||||
})
|
||||
|
||||
// 组件卸载
|
||||
onUnmounted(() => {
|
||||
if (recordingTimer) {
|
||||
clearInterval(recordingTimer)
|
||||
}
|
||||
|
||||
if (animationId) {
|
||||
cancelAnimationFrame(animationId)
|
||||
}
|
||||
|
||||
if (mediaRecorder && mediaRecorder.stream) {
|
||||
mediaRecorder.stream.getTracks().forEach(track => track.stop())
|
||||
}
|
||||
|
||||
if (audioContext && audioContext.state !== 'closed') {
|
||||
audioContext.close()
|
||||
}
|
||||
|
||||
clearRecording()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.audio-recorder {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.recorder-content {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.recorder-status {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid #e4e7ed;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto 15px;
|
||||
transition: all 0.3s ease;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.status-indicator.ready {
|
||||
border-color: #67c23a;
|
||||
background: #f0f9ff;
|
||||
}
|
||||
|
||||
.status-indicator.active {
|
||||
border-color: #e6a23c;
|
||||
background: #fef0e6;
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
box-shadow: 0 0 0 0 rgba(230, 162, 60, 0.7);
|
||||
}
|
||||
70% {
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 0 0 10px rgba(230, 162, 60, 0);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
box-shadow: 0 0 0 0 rgba(230, 162, 60, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.status-icon {
|
||||
font-size: 2.5rem;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.status-indicator.ready .status-icon {
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
.status-indicator.active .status-icon {
|
||||
color: #e6a23c;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.primary-text {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.secondary-text {
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.recorder-controls {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.record-button,
|
||||
.stop-button {
|
||||
min-width: 120px;
|
||||
height: 45px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.recorder-settings {
|
||||
margin-bottom: 25px;
|
||||
padding: 15px;
|
||||
background: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.audio-visualizer {
|
||||
margin-bottom: 25px;
|
||||
padding: 15px;
|
||||
background: #f0f0f0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.visualizer-canvas {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
border-radius: 4px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.audio-preview {
|
||||
margin-top: 25px;
|
||||
padding: 20px;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 8px;
|
||||
background: #f9f9f9;
|
||||
}
|
||||
|
||||
.preview-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 15px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.preview-header span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.preview-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.audio-player {
|
||||
width: 100%;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.preview-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.submit-button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 480px) {
|
||||
.status-indicator {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.status-icon {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.record-button,
|
||||
.stop-button {
|
||||
min-width: 100px;
|
||||
height: 40px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,941 @@
|
||||
<template>
|
||||
<div class="prediction-result" v-if="result">
|
||||
<!-- 主要预测结果卡片 -->
|
||||
<div class="main-result-card">
|
||||
<div class="result-header">
|
||||
<div class="result-icon">
|
||||
<el-icon><TrophyBase /></el-icon>
|
||||
</div>
|
||||
<div class="result-title">
|
||||
<h3>识别结果</h3>
|
||||
<p>深度学习模型分析完成</p>
|
||||
</div>
|
||||
<div class="result-actions">
|
||||
<el-button type="primary" size="small" @click="exportResult" class="action-btn">
|
||||
<template #icon><el-icon><Download /></el-icon></template>
|
||||
导出
|
||||
</el-button>
|
||||
<el-button size="small" @click="shareResult" class="action-btn">
|
||||
<template #icon><el-icon><Share /></el-icon></template>
|
||||
分享
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主要预测结果展示 -->
|
||||
<div class="main-prediction">
|
||||
<div class="prediction-badge">
|
||||
<div class="badge-icon">
|
||||
<el-icon><Star /></el-icon>
|
||||
</div>
|
||||
<div class="badge-content">
|
||||
<div class="predicted-class">{{ result.predicted_class || result.label }}</div>
|
||||
<div class="confidence-score">
|
||||
置信度: <span class="confidence-value">{{ ((result.confidence || result.score) * 100).toFixed(2) }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="confidence-ring">
|
||||
<svg class="ring-svg" viewBox="0 0 100 100">
|
||||
<circle
|
||||
class="ring-background"
|
||||
cx="50"
|
||||
cy="50"
|
||||
r="40"
|
||||
fill="none"
|
||||
stroke="rgba(255, 255, 255, 0.2)"
|
||||
stroke-width="8"
|
||||
/>
|
||||
<circle
|
||||
class="ring-progress"
|
||||
cx="50"
|
||||
cy="50"
|
||||
r="40"
|
||||
fill="none"
|
||||
stroke="url(#gradient)"
|
||||
stroke-width="8"
|
||||
stroke-linecap="round"
|
||||
:stroke-dasharray="circumference"
|
||||
:stroke-dashoffset="strokeDashoffset"
|
||||
transform="rotate(-90 50 50)"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" style="stop-color:#52c41a"/>
|
||||
<stop offset="100%" style="stop-color:#73d13d"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
<div class="ring-text">{{ Math.round((result.confidence || result.score) * 100) }}%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 详细信息卡片 -->
|
||||
<div class="details-card">
|
||||
<div class="details-header">
|
||||
<el-icon><InfoFilled /></el-icon>
|
||||
<span>详细信息</span>
|
||||
</div>
|
||||
<div class="details-grid">
|
||||
<div class="detail-item">
|
||||
<div class="detail-icon">
|
||||
<el-icon><Flag /></el-icon>
|
||||
</div>
|
||||
<div class="detail-content">
|
||||
<div class="detail-label">预测类别</div>
|
||||
<div class="detail-value">{{ result.predicted_class || result.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-item">
|
||||
<div class="detail-icon">
|
||||
<el-icon><DataAnalysis /></el-icon>
|
||||
</div>
|
||||
<div class="detail-content">
|
||||
<div class="detail-label">置信度</div>
|
||||
<div class="detail-value">{{ ((result.confidence || result.score) * 100).toFixed(2) }}%</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-item">
|
||||
<div class="detail-icon">
|
||||
<el-icon><Timer /></el-icon>
|
||||
</div>
|
||||
<div class="detail-content">
|
||||
<div class="detail-label">预测时间</div>
|
||||
<div class="detail-value">{{ formatTime(result.timestamp) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-item">
|
||||
<div class="detail-icon">
|
||||
<el-icon><Headphone /></el-icon>
|
||||
</div>
|
||||
<div class="detail-content">
|
||||
<div class="detail-label">音频时长</div>
|
||||
<div class="detail-value">{{ formatDuration(result.audio_info?.duration) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 概率分布图表 -->
|
||||
<div v-if="result.all_probabilities" class="probability-card">
|
||||
<div class="probability-header">
|
||||
<el-icon><PieChart /></el-icon>
|
||||
<span>所有类别概率分布</span>
|
||||
<el-button type="text" size="small" @click="toggleChartView" class="toggle-view">
|
||||
<el-icon><Switch /></el-icon>
|
||||
{{ showChart ? '列表视图' : '图表视图' }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 图表视图 -->
|
||||
<transition name="fade">
|
||||
<div v-if="showChart" class="chart-container">
|
||||
<div ref="chartContainer" class="echarts-chart"></div>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<!-- 列表视图 -->
|
||||
<transition name="fade">
|
||||
<div v-if="!showChart" class="probability-list">
|
||||
<div
|
||||
v-for="(prob, className) in sortedProbabilities"
|
||||
:key="className"
|
||||
class="probability-item"
|
||||
:class="{ active: className === (result.predicted_class || result.label) }"
|
||||
>
|
||||
<div class="prob-info">
|
||||
<div class="class-name">
|
||||
<span class="name-text">{{ className }}</span>
|
||||
<el-tag v-if="className === (result.predicted_class || result.label)"
|
||||
size="small" type="success" class="winner-tag">
|
||||
<el-icon><Trophy /></el-icon>
|
||||
最高
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="prob-value">{{ (prob * 100).toFixed(2) }}%</div>
|
||||
</div> <div class="prob-bar-container">
|
||||
<div class="prob-bar">
|
||||
<div
|
||||
class="prob-fill"
|
||||
:style="{
|
||||
width: `${prob * 100}%`,
|
||||
background: getProgressColor(prob, className === (result.predicted_class || result.label))
|
||||
}"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="no-result">
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon">
|
||||
<el-icon><Document /></el-icon>
|
||||
</div>
|
||||
<h3>暂无预测结果</h3>
|
||||
<p>请上传音频文件或录制音频进行识别</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch, onMounted, nextTick, onBeforeUnmount } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import * as echarts from 'echarts'
|
||||
|
||||
const props = defineProps({
|
||||
result: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
// 响应式数据
|
||||
const chartContainer = ref(null)
|
||||
const showChart = ref(false)
|
||||
let chartInstance = null
|
||||
|
||||
// 计算属性
|
||||
const circumference = computed(() => 2 * Math.PI * 40) // r=40的圆周长
|
||||
|
||||
const strokeDashoffset = computed(() => {
|
||||
if (!props.result) return circumference.value
|
||||
const confidence = props.result.confidence || props.result.score || 0
|
||||
return circumference.value - (confidence * circumference.value)
|
||||
})
|
||||
|
||||
const sortedProbabilities = computed(() => {
|
||||
if (!props.result?.all_probabilities) return {}
|
||||
|
||||
const entries = Object.entries(props.result.all_probabilities)
|
||||
entries.sort((a, b) => b[1] - a[1]) // 按概率降序排列
|
||||
|
||||
return Object.fromEntries(entries)
|
||||
})
|
||||
|
||||
// 格式化函数
|
||||
const formatTime = (timestamp) => {
|
||||
if (!timestamp) return 'N/A'
|
||||
try {
|
||||
if (typeof timestamp === 'string') {
|
||||
return timestamp
|
||||
}
|
||||
return new Date(timestamp).toLocaleString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit'
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('时间格式化错误:', error)
|
||||
return 'N/A'
|
||||
}
|
||||
}
|
||||
|
||||
const formatDuration = (seconds) => {
|
||||
if (!seconds && seconds !== 0) return 'N/A'
|
||||
|
||||
try {
|
||||
const duration = parseFloat(seconds)
|
||||
if (isNaN(duration)) return 'N/A'
|
||||
|
||||
if (duration < 60) {
|
||||
return `${duration.toFixed(1)}秒`
|
||||
}
|
||||
|
||||
const minutes = Math.floor(duration / 60)
|
||||
const remainingSeconds = (duration % 60).toFixed(1)
|
||||
return `${minutes}分${remainingSeconds}秒`
|
||||
} catch (error) {
|
||||
console.error('时长格式化错误:', error)
|
||||
return 'N/A'
|
||||
}
|
||||
}
|
||||
|
||||
const getProgressColor = (prob, isWinner = false) => {
|
||||
if (isWinner) {
|
||||
return 'linear-gradient(135deg, #52c41a, #73d13d)'
|
||||
}
|
||||
if (prob > 0.7) return 'linear-gradient(135deg, #52c41a, #73d13d)'
|
||||
if (prob > 0.4) return 'linear-gradient(135deg, #fadb14, #ffec3d)'
|
||||
if (prob > 0.2) return 'linear-gradient(135deg, #fa8c16, #ffa940)'
|
||||
return 'linear-gradient(135deg, #ff4d4f, #ff7875)'
|
||||
}
|
||||
|
||||
const initChart = () => {
|
||||
if (!props.result?.all_probabilities || !chartContainer.value) return
|
||||
|
||||
if (chartInstance) {
|
||||
chartInstance.dispose()
|
||||
}
|
||||
|
||||
chartInstance = echarts.init(chartContainer.value)
|
||||
|
||||
const data = Object.entries(props.result.all_probabilities)
|
||||
.map(([name, value]) => ({ name, value: (value * 100).toFixed(2) }))
|
||||
.sort((a, b) => b.value - a.value)
|
||||
|
||||
const option = {
|
||||
title: {
|
||||
text: '类别置信度分布',
|
||||
left: 'center'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c}%'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: 'left'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '置信度',
|
||||
type: 'pie',
|
||||
radius: '50%',
|
||||
data: data,
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
chartInstance.setOption(option)
|
||||
}
|
||||
|
||||
const exportResult = () => {
|
||||
try {
|
||||
const exportData = {
|
||||
predicted_class: props.result.predicted_class,
|
||||
confidence: props.result.confidence,
|
||||
timestamp: props.result.timestamp,
|
||||
all_probabilities: props.result.all_probabilities
|
||||
}
|
||||
|
||||
const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = `prediction_result_${Date.now()}.json`
|
||||
a.click()
|
||||
URL.revokeObjectURL(url)
|
||||
|
||||
ElMessage.success('结果导出成功')
|
||||
} catch (error) {
|
||||
ElMessage.error('导出失败: ' + error.message)
|
||||
}
|
||||
}
|
||||
|
||||
const shareResult = () => {
|
||||
const shareText = `音频分类结果: ${props.result.predicted_class} (置信度: ${(props.result.confidence * 100).toFixed(2)}%)`
|
||||
|
||||
if (navigator.share) {
|
||||
navigator.share({
|
||||
title: '音频分类结果',
|
||||
text: shareText
|
||||
})
|
||||
} else {
|
||||
navigator.clipboard.writeText(shareText).then(() => {
|
||||
ElMessage.success('结果已复制到剪贴板')
|
||||
}).catch(() => {
|
||||
ElMessage.error('复制失败')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
watch(() => props.result, () => {
|
||||
if (props.result) {
|
||||
nextTick(() => {
|
||||
initChart()
|
||||
})
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
onMounted(() => {
|
||||
if (props.result) {
|
||||
nextTick(() => {
|
||||
initChart()
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 预测结果主容器 */
|
||||
.prediction-result {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 25px;
|
||||
animation: fadeInUp 0.6s ease-out;
|
||||
}
|
||||
|
||||
/* 主要结果卡片 */
|
||||
.main-result-card {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 20px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.main-result-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||||
transition: left 0.5s ease;
|
||||
}
|
||||
|
||||
.main-result-card:hover::before {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
.main-result-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
/* 结果头部 */
|
||||
.result-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.result-icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background: linear-gradient(135deg, #52c41a, #73d13d);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 1.5rem;
|
||||
box-shadow: 0 8px 25px rgba(82, 196, 26, 0.3);
|
||||
animation: pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.result-title h3 {
|
||||
color: white;
|
||||
font-size: 1.8rem;
|
||||
font-weight: 700;
|
||||
margin: 0 0 5px 0;
|
||||
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.result-title p {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.result-actions {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
background: rgba(255, 255, 255, 0.1) !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.3) !important;
|
||||
color: white !important;
|
||||
transition: all 0.3s ease;
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 12px !important;
|
||||
}
|
||||
|
||||
.action-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.2) !important;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/* 主要预测结果 */
|
||||
.main-prediction {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.prediction-badge {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 25px;
|
||||
padding: 25px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 20px;
|
||||
backdrop-filter: blur(15px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.badge-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
background: linear-gradient(135deg, #fadb14, #ffec3d);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 1.8rem;
|
||||
box-shadow: 0 8px 25px rgba(250, 219, 20, 0.4);
|
||||
}
|
||||
|
||||
.badge-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.predicted-class {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
margin-bottom: 8px;
|
||||
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.confidence-score {
|
||||
font-size: 1.2rem;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.confidence-value {
|
||||
font-weight: 700;
|
||||
color: #52c41a;
|
||||
text-shadow: 0 0 10px rgba(82, 196, 26, 0.5);
|
||||
}
|
||||
|
||||
/* 置信度环形图 */
|
||||
.confidence-ring {
|
||||
position: relative;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.ring-svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.ring-background {
|
||||
stroke: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.ring-progress {
|
||||
stroke: url(#gradient);
|
||||
stroke-linecap: round;
|
||||
transition: stroke-dashoffset 1s ease-in-out;
|
||||
}
|
||||
|
||||
.ring-text {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 1.2rem;
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* 详细信息卡片 */
|
||||
.details-card {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 16px;
|
||||
padding: 25px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.details-card:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.details-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
color: white;
|
||||
font-size: 1.3rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.details-header .el-icon {
|
||||
color: #409eff;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.details-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
padding: 20px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.detail-item:hover {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.detail-icon {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
background: linear-gradient(135deg, #409eff, #52c41a);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 1.2rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.detail-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-size: 0.9rem;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 概率分布卡片 */
|
||||
.probability-card {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 16px;
|
||||
padding: 25px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.probability-card:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.probability-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 25px;
|
||||
color: white;
|
||||
font-size: 1.3rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.probability-header .el-icon {
|
||||
color: #fa8c16;
|
||||
font-size: 1.4rem;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.toggle-view {
|
||||
background: rgba(255, 255, 255, 0.1) !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.3) !important;
|
||||
color: white !important;
|
||||
border-radius: 8px !important;
|
||||
}
|
||||
|
||||
.toggle-view:hover {
|
||||
background: rgba(255, 255, 255, 0.2) !important;
|
||||
}
|
||||
|
||||
/* 图表容器 */
|
||||
.chart-container {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.echarts-chart {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
/* 概率列表 */
|
||||
.probability-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.probability-item {
|
||||
padding: 20px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.probability-item:hover {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
transform: translateX(5px);
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.probability-item.active {
|
||||
background: rgba(82, 196, 26, 0.2);
|
||||
border-color: rgba(82, 196, 26, 0.5);
|
||||
box-shadow: 0 0 20px rgba(82, 196, 26, 0.3);
|
||||
}
|
||||
|
||||
.prob-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.class-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.name-text {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.winner-tag {
|
||||
background: rgba(82, 196, 26, 0.2) !important;
|
||||
border-color: rgba(82, 196, 26, 0.5) !important;
|
||||
color: #52c41a !important;
|
||||
}
|
||||
|
||||
.prob-value {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.prob-bar-container {
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.prob-bar {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.prob-fill {
|
||||
height: 100%;
|
||||
border-radius: 4px;
|
||||
transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
background: linear-gradient(90deg, #52c41a, #73d13d);
|
||||
position: relative;
|
||||
animation: progressFill 1s ease-out;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.no-result {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
animation: fadeIn 0.6s ease-out;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 4rem;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
margin-bottom: 20px;
|
||||
animation: float 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.empty-state h3 {
|
||||
color: white;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 10px;
|
||||
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
font-size: 1.1rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 动画 */
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%, 100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes progressFill {
|
||||
from {
|
||||
width: 0%;
|
||||
}
|
||||
to {
|
||||
width: var(--target-width, 100%);
|
||||
}
|
||||
}
|
||||
|
||||
/* 过渡动画 */
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.prediction-result {
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.main-result-card {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.result-header {
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.prediction-badge {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.details-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.prob-info {
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.echarts-chart {
|
||||
height: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.main-result-card,
|
||||
.details-card,
|
||||
.probability-card {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.predicted-class {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.confidence-ring {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.probability-item {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,18 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import ElementPlus from 'element-plus'
|
||||
import 'element-plus/dist/index.css'
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
// 注册所有图标
|
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||
app.component(key, component)
|
||||
}
|
||||
|
||||
app.use(ElementPlus)
|
||||
app.use(router)
|
||||
|
||||
app.mount('#app')
|
||||
@ -0,0 +1,17 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import HomePage from '../views/HomePage.vue'
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'Home',
|
||||
component: HomePage
|
||||
}
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes
|
||||
})
|
||||
|
||||
export default router
|
||||
@ -0,0 +1,33 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import AutoImport from 'unplugin-auto-import/vite'
|
||||
import Components from 'unplugin-vue-components/vite'
|
||||
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
AutoImport({
|
||||
resolvers: [ElementPlusResolver()],
|
||||
}),
|
||||
Components({
|
||||
resolvers: [ElementPlusResolver()],
|
||||
}),
|
||||
],
|
||||
server: {
|
||||
port: 3000,
|
||||
host: '0.0.0.0',
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:5000',
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
}
|
||||
}
|
||||
},
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
assetsDir: 'assets',
|
||||
chunkSizeWarningLimit: 1000
|
||||
}
|
||||
})
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,24 @@
|
||||
@echo off
|
||||
echo ================================
|
||||
echo 声纹识别系统启动脚本
|
||||
echo ================================
|
||||
echo.
|
||||
|
||||
echo 正在启动后端服务...
|
||||
cd /d "%~dp0backend"
|
||||
start "后端服务" cmd /k "python app.py"
|
||||
|
||||
echo 等待后端服务启动...
|
||||
timeout /t 3 /nobreak >nul
|
||||
|
||||
echo 正在启动前端服务...
|
||||
cd /d "%~dp0frontend"
|
||||
start "前端服务" cmd /k "npm run dev"
|
||||
|
||||
echo.
|
||||
echo 启动完成!
|
||||
echo 后端服务: http://localhost:5000
|
||||
echo 前端服务: http://localhost:3000
|
||||
echo.
|
||||
echo 请等待服务完全启动后访问前端地址
|
||||
pause
|
||||
@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "================================"
|
||||
echo " 声纹识别系统启动脚本"
|
||||
echo "================================"
|
||||
echo
|
||||
|
||||
# 获取脚本所在目录
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
echo "正在启动后端服务..."
|
||||
cd "$SCRIPT_DIR/backend"
|
||||
python app.py &
|
||||
BACKEND_PID=$!
|
||||
|
||||
echo "等待后端服务启动..."
|
||||
sleep 3
|
||||
|
||||
echo "正在启动前端服务..."
|
||||
cd "$SCRIPT_DIR/frontend"
|
||||
npm run dev &
|
||||
FRONTEND_PID=$!
|
||||
|
||||
echo
|
||||
echo "启动完成!"
|
||||
echo "后端服务: http://localhost:5000"
|
||||
echo "前端服务: http://localhost:3000"
|
||||
echo
|
||||
echo "后端进程 PID: $BACKEND_PID"
|
||||
echo "前端进程 PID: $FRONTEND_PID"
|
||||
echo
|
||||
echo "按 Ctrl+C 停止所有服务"
|
||||
|
||||
# 等待用户中断
|
||||
trap 'echo "正在停止服务..."; kill $BACKEND_PID $FRONTEND_PID; exit' INT
|
||||
wait
|
||||
@ -0,0 +1,46 @@
|
||||
# 语速增强
|
||||
speed:
|
||||
# 增强概率
|
||||
prob: 1.0
|
||||
|
||||
# 音量增强
|
||||
volume:
|
||||
# 增强概率
|
||||
prob: 0.0
|
||||
# 最小增益
|
||||
min_gain_dBFS: -15
|
||||
# 最大增益
|
||||
max_gain_dBFS: 15
|
||||
|
||||
# 噪声增强
|
||||
noise:
|
||||
# 增强概率
|
||||
prob: 0.5
|
||||
# 噪声增强的噪声文件夹
|
||||
noise_dir: 'dataset/noise'
|
||||
# 针对噪声的最小音量增益
|
||||
min_snr_dB: 10
|
||||
# 针对噪声的最大音量增益
|
||||
max_snr_dB: 50
|
||||
|
||||
# 混响增强
|
||||
reverb:
|
||||
# 增强概率
|
||||
prob: 0.5
|
||||
# 混响增强的混响文件夹
|
||||
reverb_dir: 'dataset/reverb'
|
||||
|
||||
# Spec增强
|
||||
spec_aug:
|
||||
# 增强概率
|
||||
prob: 0.5
|
||||
# 频域掩蔽的比例
|
||||
freq_mask_ratio: 0.1
|
||||
# 频域掩蔽次数
|
||||
n_freq_masks: 1
|
||||
# 频域掩蔽的比例
|
||||
time_mask_ratio: 0.05
|
||||
# 频域掩蔽次数
|
||||
n_time_masks: 1
|
||||
# 最大时间扭曲
|
||||
max_time_warp: 0
|
||||
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 115 KiB |
@ -0,0 +1,19 @@
|
||||
import argparse
|
||||
import functools
|
||||
|
||||
from macls.trainer import MAClsTrainer
|
||||
from macls.utils.utils import add_arguments, print_arguments
|
||||
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
add_arg = functools.partial(add_arguments, argparser=parser)
|
||||
add_arg('configs', str, 'configs/cam++.yml', '配置文件')
|
||||
add_arg('save_dir', str, 'dataset/features', '保存特征的路径')
|
||||
add_arg('max_duration', int, 100, '提取特征的最大时长,避免过长显存不足,单位秒')
|
||||
args = parser.parse_args()
|
||||
print_arguments(args=args)
|
||||
|
||||
# 获取训练器
|
||||
trainer = MAClsTrainer(configs=args.configs)
|
||||
|
||||
# 提取特征保存文件
|
||||
trainer.extract_features(save_dir=args.save_dir, max_duration=args.max_duration)
|
||||
@ -0,0 +1,23 @@
|
||||
import argparse
|
||||
import functools
|
||||
|
||||
from macls.predict import MAClsPredictor
|
||||
from macls.utils.utils import add_arguments, print_arguments
|
||||
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
add_arg = functools.partial(add_arguments, argparser=parser)
|
||||
add_arg('configs', str, 'configs/cam++.yml', '配置文件')
|
||||
add_arg('use_gpu', bool, True, '是否使用GPU预测')
|
||||
add_arg('audio_path', str, 'dataset/UrbanSound8K/audio/fold5/156634-5-2-5.wav', '音频路径')
|
||||
add_arg('model_path', str, 'models/CAMPPlus_Fbank/best_model/', '导出的预测模型文件路径')
|
||||
args = parser.parse_args()
|
||||
print_arguments(args=args)
|
||||
|
||||
# 获取识别器
|
||||
predictor = MAClsPredictor(configs=args.configs,
|
||||
model_path=args.model_path,
|
||||
use_gpu=args.use_gpu)
|
||||
|
||||
label, score = predictor.predict(audio_data=args.audio_path)
|
||||
|
||||
print(f'音频:{args.audio_path} 的预测结果标签为:{label},得分:{score}')
|
||||
@ -0,0 +1,58 @@
|
||||
import argparse
|
||||
import functools
|
||||
import threading
|
||||
import time
|
||||
|
||||
import numpy as np
|
||||
import soundcard as sc
|
||||
|
||||
from macls.predict import MAClsPredictor
|
||||
from macls.utils.utils import add_arguments, print_arguments
|
||||
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
add_arg = functools.partial(add_arguments, argparser=parser)
|
||||
add_arg('configs', str, 'configs/cam++.yml', '配置文件')
|
||||
add_arg('use_gpu', bool, True, '是否使用GPU预测')
|
||||
add_arg('record_seconds', float, 3, '录音长度')
|
||||
add_arg('model_path', str, 'models/CAMPPlus_Fbank/best_model/', '导出的预测模型文件路径')
|
||||
args = parser.parse_args()
|
||||
print_arguments(args=args)
|
||||
|
||||
# 获取识别器
|
||||
predictor = MAClsPredictor(configs=args.configs,
|
||||
model_path=args.model_path,
|
||||
use_gpu=args.use_gpu)
|
||||
|
||||
all_data = []
|
||||
# 获取默认麦克风
|
||||
default_mic = sc.default_microphone()
|
||||
# 录音采样率
|
||||
samplerate = 16000
|
||||
# 录音块大小
|
||||
numframes = 1024
|
||||
# 模型输入长度
|
||||
infer_len = int(samplerate * args.record_seconds / numframes)
|
||||
|
||||
|
||||
def infer_thread():
|
||||
global all_data
|
||||
s = time.time()
|
||||
while True:
|
||||
if len(all_data) < infer_len: continue
|
||||
# 截取最新的音频数据
|
||||
seg_data = all_data[-infer_len:]
|
||||
d = np.concatenate(seg_data)
|
||||
# 删除旧的音频数据
|
||||
del all_data[:len(all_data) - infer_len]
|
||||
label, score = predictor.predict(audio_data=d, sample_rate=samplerate)
|
||||
print(f'{int(time.time() - s)}s 预测结果标签为:{label},得分:{score}')
|
||||
|
||||
|
||||
thread = threading.Thread(target=infer_thread, args=())
|
||||
thread.start()
|
||||
|
||||
|
||||
with default_mic.recorder(samplerate=samplerate, channels=1) as mic:
|
||||
while True:
|
||||
data = mic.record(numframes=numframes)
|
||||
all_data.append(data)
|
||||
@ -0,0 +1 @@
|
||||
__version__ = "1.0.6"
|
||||
@ -0,0 +1,132 @@
|
||||
import numpy as np
|
||||
import torch
|
||||
import torchaudio.compliance.kaldi as Kaldi
|
||||
from torch import nn
|
||||
from torchaudio.transforms import MelSpectrogram, Spectrogram, MFCC
|
||||
from loguru import logger
|
||||
|
||||
|
||||
class AudioFeaturizer(nn.Module):
|
||||
"""音频特征器
|
||||
|
||||
:param feature_method: 所使用的预处理方法
|
||||
:type feature_method: str
|
||||
:param use_hf_model: 是否使用HF上的Wav2Vec2类似模型提取音频特征
|
||||
:type use_hf_model: bool
|
||||
:param method_args: 预处理方法的参数
|
||||
:type method_args: dict
|
||||
"""
|
||||
|
||||
def __init__(self, feature_method='MelSpectrogram', use_hf_model=False, method_args={}):
|
||||
super().__init__()
|
||||
self._method_args = method_args
|
||||
self._feature_method = feature_method
|
||||
self.use_hf_model = use_hf_model
|
||||
if self.use_hf_model:
|
||||
from transformers import AutoModel, AutoFeatureExtractor
|
||||
# 判断是否使用GPU提取特征
|
||||
use_gpu = torch.cuda.is_available() and method_args.get('use_gpu', True)
|
||||
self.device = torch.device("cuda") if use_gpu else torch.device("cpu")
|
||||
# 加载Wav2Vec2类似模型
|
||||
self.processor = AutoFeatureExtractor.from_pretrained(feature_method)
|
||||
self.feature_model = AutoModel.from_pretrained(feature_method).to(self.device)
|
||||
logger.info(f'使用模型【{feature_method}】提取特征,使用【{self.device}】设备提取')
|
||||
# 获取模型的输出通道数
|
||||
inputs = self.processor(np.ones(16000 * 1, dtype=np.float32), sampling_rate=16000,
|
||||
return_tensors="pt").to(self.device)
|
||||
with torch.no_grad():
|
||||
outputs = self.feature_model(**inputs)
|
||||
self.output_channels = outputs.extract_features.shape[2]
|
||||
else:
|
||||
if feature_method == 'MelSpectrogram':
|
||||
self.feat_fun = MelSpectrogram(**method_args)
|
||||
elif feature_method == 'Spectrogram':
|
||||
self.feat_fun = Spectrogram(**method_args)
|
||||
elif feature_method == 'MFCC':
|
||||
self.feat_fun = MFCC(**method_args)
|
||||
elif feature_method == 'Fbank':
|
||||
self.feat_fun = KaldiFbank(**method_args)
|
||||
else:
|
||||
raise Exception(f'预处理方法 {self._feature_method} 不存在!')
|
||||
logger.info(f'使用【{feature_method}】提取特征')
|
||||
|
||||
def forward(self, waveforms, input_lens_ratio=None):
|
||||
"""从AudioSegment中提取音频特征
|
||||
|
||||
:param waveforms: Audio segment to extract features from.
|
||||
:type waveforms: AudioSegment
|
||||
:param input_lens_ratio: input length ratio
|
||||
:type input_lens_ratio: tensor
|
||||
:return: Spectrogram audio feature in 2darray.
|
||||
:rtype: ndarray
|
||||
"""
|
||||
if len(waveforms.shape) == 1:
|
||||
waveforms = waveforms.unsqueeze(0)
|
||||
if self.use_hf_model:
|
||||
# 使用HF上的Wav2Vec2类似模型提取音频特征
|
||||
if isinstance(waveforms, torch.Tensor):
|
||||
waveforms = waveforms.numpy()
|
||||
inputs = self.processor(waveforms, sampling_rate=16000,
|
||||
return_tensors="pt").to(self.device)
|
||||
with torch.no_grad():
|
||||
outputs = self.feature_model(**inputs)
|
||||
feature = outputs.extract_features.cpu().detach()
|
||||
else:
|
||||
# 使用普通方法提取音频特征
|
||||
feature = self.feat_fun(waveforms)
|
||||
feature = feature.transpose(2, 1)
|
||||
# 归一化
|
||||
feature = feature - feature.mean(1, keepdim=True)
|
||||
if input_lens_ratio is not None:
|
||||
# 对掩码比例进行扩展
|
||||
input_lens = (input_lens_ratio * feature.shape[1])
|
||||
mask_lens = torch.round(input_lens).long()
|
||||
mask_lens = mask_lens.unsqueeze(1)
|
||||
# 生成掩码张量
|
||||
idxs = torch.arange(feature.shape[1], device=feature.device).repeat(feature.shape[0], 1)
|
||||
mask = idxs < mask_lens
|
||||
mask = mask.unsqueeze(-1)
|
||||
# 对特征进行掩码操作
|
||||
feature = torch.where(mask, feature, torch.zeros_like(feature))
|
||||
return feature
|
||||
|
||||
@property
|
||||
def feature_dim(self):
|
||||
"""返回特征大小
|
||||
|
||||
:return: 特征大小
|
||||
:rtype: int
|
||||
"""
|
||||
if self.use_hf_model:
|
||||
return self.output_channels
|
||||
if self._feature_method == 'MelSpectrogram':
|
||||
return self._method_args.get('n_mels', 128)
|
||||
elif self._feature_method == 'Spectrogram':
|
||||
return self._method_args.get('n_fft', 400) // 2 + 1
|
||||
elif self._feature_method == 'MFCC':
|
||||
return self._method_args.get('n_mfcc', 40)
|
||||
elif self._feature_method == 'Fbank':
|
||||
return self._method_args.get('num_mel_bins', 23)
|
||||
else:
|
||||
raise Exception('没有{}预处理方法'.format(self._feature_method))
|
||||
|
||||
|
||||
class KaldiFbank(nn.Module):
|
||||
def __init__(self, **kwargs):
|
||||
super(KaldiFbank, self).__init__()
|
||||
self.kwargs = kwargs
|
||||
|
||||
def forward(self, waveforms):
|
||||
"""
|
||||
:param waveforms: [Batch, Length]
|
||||
:return: [Batch, Feature, Length]
|
||||
"""
|
||||
log_fbanks = []
|
||||
for waveform in waveforms:
|
||||
if len(waveform.shape) == 1:
|
||||
waveform = waveform.unsqueeze(0)
|
||||
log_fbank = Kaldi.fbank(waveform, **self.kwargs)
|
||||
log_fbank = log_fbank.transpose(0, 1)
|
||||
log_fbanks.append(log_fbank)
|
||||
log_fbank = torch.stack(log_fbanks)
|
||||
return log_fbank
|
||||
@ -0,0 +1,12 @@
|
||||
import numpy as np
|
||||
import torch
|
||||
|
||||
|
||||
# 计算准确率
|
||||
def accuracy(output, label):
|
||||
output = torch.nn.functional.softmax(output, dim=-1)
|
||||
output = output.data.cpu().numpy()
|
||||
output = np.argmax(output, axis=1)
|
||||
label = label.data.cpu().numpy()
|
||||
acc = np.mean((output == label).astype(int))
|
||||
return acc
|
||||
@ -0,0 +1,32 @@
|
||||
import importlib
|
||||
|
||||
from loguru import logger
|
||||
from torch.optim import *
|
||||
from .scheduler import WarmupCosineSchedulerLR
|
||||
from torch.optim.lr_scheduler import *
|
||||
|
||||
__all__ = ['build_optimizer', 'build_lr_scheduler']
|
||||
|
||||
|
||||
def build_optimizer(params, configs):
|
||||
use_optimizer = configs.optimizer_conf.get('optimizer', 'Adam')
|
||||
optimizer_args = configs.optimizer_conf.get('optimizer_args', {})
|
||||
optim = importlib.import_module(__name__)
|
||||
optimizer = getattr(optim, use_optimizer)(params=params, **optimizer_args)
|
||||
logger.info(f'成功创建优化方法:{use_optimizer},参数为:{optimizer_args}')
|
||||
return optimizer
|
||||
|
||||
|
||||
def build_lr_scheduler(optimizer, step_per_epoch, configs):
|
||||
use_scheduler = configs.optimizer_conf.get('scheduler', 'WarmupCosineSchedulerLR')
|
||||
scheduler_args = configs.optimizer_conf.get('scheduler_args', {})
|
||||
if configs.optimizer_conf.scheduler == 'CosineAnnealingLR' and 'T_max' not in scheduler_args:
|
||||
scheduler_args.T_max = int(configs.train_conf.max_epoch * 1.2) * step_per_epoch
|
||||
if configs.optimizer_conf.scheduler == 'WarmupCosineSchedulerLR' and 'fix_epoch' not in scheduler_args:
|
||||
scheduler_args.fix_epoch = configs.train_conf.max_epoch
|
||||
if configs.optimizer_conf.scheduler == 'WarmupCosineSchedulerLR' and 'step_per_epoch' not in scheduler_args:
|
||||
scheduler_args.step_per_epoch = step_per_epoch
|
||||
optim = importlib.import_module(__name__)
|
||||
scheduler = getattr(optim, use_scheduler)(optimizer=optimizer, **scheduler_args)
|
||||
logger.info(f'成功创建学习率衰减:{use_scheduler},参数为:{scheduler_args}')
|
||||
return scheduler
|
||||
@ -0,0 +1,48 @@
|
||||
import math
|
||||
from typing import List
|
||||
|
||||
|
||||
class WarmupCosineSchedulerLR:
|
||||
def __init__(
|
||||
self,
|
||||
optimizer,
|
||||
min_lr,
|
||||
max_lr,
|
||||
warmup_epoch,
|
||||
fix_epoch,
|
||||
step_per_epoch
|
||||
):
|
||||
self.optimizer = optimizer
|
||||
assert min_lr <= max_lr
|
||||
self.min_lr = min_lr
|
||||
self.max_lr = max_lr
|
||||
self.warmup_step = warmup_epoch * step_per_epoch
|
||||
self.fix_step = fix_epoch * step_per_epoch
|
||||
self.current_step = 0.0
|
||||
|
||||
def set_lr(self, ):
|
||||
new_lr = self.clr(self.current_step)
|
||||
for param_group in self.optimizer.param_groups:
|
||||
param_group['lr'] = new_lr
|
||||
return new_lr
|
||||
|
||||
def step(self, step=None):
|
||||
if step is not None:
|
||||
self.current_step = step
|
||||
new_lr = self.set_lr()
|
||||
self.current_step += 1
|
||||
return new_lr
|
||||
|
||||
def clr(self, step):
|
||||
if step < self.warmup_step:
|
||||
return self.min_lr + (self.max_lr - self.min_lr) * \
|
||||
(step / self.warmup_step)
|
||||
elif self.warmup_step <= step < self.fix_step:
|
||||
return self.min_lr + 0.5 * (self.max_lr - self.min_lr) * \
|
||||
(1 + math.cos(math.pi * (step - self.warmup_step) /
|
||||
(self.fix_step - self.warmup_step)))
|
||||
else:
|
||||
return self.min_lr
|
||||
|
||||
def get_last_lr(self) -> List[float]:
|
||||
return [self.clr(self.current_step)]
|
||||
@ -0,0 +1,162 @@
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
|
||||
import torch
|
||||
from loguru import logger
|
||||
from macls import __version__
|
||||
|
||||
|
||||
def load_pretrained(model, pretrained_model, use_gpu=True):
|
||||
"""加载预训练模型
|
||||
|
||||
:param model: 使用的模型
|
||||
:param pretrained_model: 预训练模型路径
|
||||
:param use_gpu: 模型是否使用GPU
|
||||
:return: 加载的模型
|
||||
"""
|
||||
# 加载预训练模型
|
||||
if pretrained_model is None: return model
|
||||
if os.path.isdir(pretrained_model):
|
||||
pretrained_model = os.path.join(pretrained_model, 'model.pth')
|
||||
assert os.path.exists(pretrained_model), f"{pretrained_model} 模型不存在!"
|
||||
if isinstance(model, torch.nn.parallel.DistributedDataParallel):
|
||||
model_dict = model.module.state_dict()
|
||||
else:
|
||||
model_dict = model.state_dict()
|
||||
if torch.cuda.is_available() and use_gpu:
|
||||
model_state_dict = torch.load(pretrained_model, weights_only=False)
|
||||
else:
|
||||
model_state_dict = torch.load(pretrained_model, weights_only=False, map_location='cpu')
|
||||
# 过滤不存在的参数
|
||||
for name, weight in model_dict.items():
|
||||
if name in model_state_dict.keys():
|
||||
if list(weight.shape) != list(model_state_dict[name].shape):
|
||||
logger.warning(f'{name} not used, shape {list(model_state_dict[name].shape)} '
|
||||
f'unmatched with {list(weight.shape)} in model.')
|
||||
model_state_dict.pop(name, None)
|
||||
# 加载权重
|
||||
if isinstance(model, torch.nn.parallel.DistributedDataParallel):
|
||||
missing_keys, unexpected_keys = model.module.load_state_dict(model_state_dict, strict=False)
|
||||
else:
|
||||
missing_keys, unexpected_keys = model.load_state_dict(model_state_dict, strict=False)
|
||||
if len(unexpected_keys) > 0:
|
||||
logger.warning('Unexpected key(s) in state_dict: {}. '
|
||||
.format(', '.join('"{}"'.format(k) for k in unexpected_keys)))
|
||||
if len(missing_keys) > 0:
|
||||
logger.warning('Missing key(s) in state_dict: {}. '
|
||||
.format(', '.join('"{}"'.format(k) for k in missing_keys)))
|
||||
logger.info('成功加载预训练模型:{}'.format(pretrained_model))
|
||||
return model
|
||||
|
||||
|
||||
def load_checkpoint(configs, model, optimizer, amp_scaler, scheduler,
|
||||
step_epoch, save_model_path, resume_model):
|
||||
"""加载模型
|
||||
|
||||
:param configs: 配置信息
|
||||
:param model: 使用的模型
|
||||
:param optimizer: 使用的优化方法
|
||||
:param amp_scaler: 使用的自动混合精度
|
||||
:param scheduler: 使用的学习率调整策略
|
||||
:param step_epoch: 每个epoch的step数量
|
||||
:param save_model_path: 模型保存路径
|
||||
:param resume_model: 恢复训练的模型路径
|
||||
"""
|
||||
last_epoch1 = 0
|
||||
accuracy1 = 0.
|
||||
|
||||
def load_model(model_path):
|
||||
assert os.path.exists(os.path.join(model_path, 'model.pth')), "模型参数文件不存在!"
|
||||
assert os.path.exists(os.path.join(model_path, 'optimizer.pth')), "优化方法参数文件不存在!"
|
||||
state_dict = torch.load(os.path.join(model_path, 'model.pth'), weights_only=False)
|
||||
if isinstance(model, torch.nn.parallel.DistributedDataParallel):
|
||||
model.module.load_state_dict(state_dict)
|
||||
else:
|
||||
model.load_state_dict(state_dict)
|
||||
optimizer.load_state_dict(torch.load(os.path.join(model_path, 'optimizer.pth'), weights_only=False))
|
||||
# 自动混合精度参数
|
||||
if amp_scaler is not None and os.path.exists(os.path.join(model_path, 'scaler.pth')):
|
||||
amp_scaler.load_state_dict(torch.load(os.path.join(model_path, 'scaler.pth')), weights_only=False)
|
||||
with open(os.path.join(model_path, 'model.state'), 'r', encoding='utf-8') as f:
|
||||
json_data = json.load(f)
|
||||
last_epoch = json_data['last_epoch']
|
||||
accuracy = json_data['accuracy']
|
||||
logger.info('成功恢复模型参数和优化方法参数:{}'.format(model_path))
|
||||
optimizer.step()
|
||||
[scheduler.step() for _ in range(last_epoch * step_epoch)]
|
||||
return last_epoch, accuracy
|
||||
|
||||
# 获取最后一个保存的模型
|
||||
save_feature_method = configs.preprocess_conf.feature_method
|
||||
if configs.preprocess_conf.get('use_hf_model', False):
|
||||
save_feature_method = save_feature_method[:-1] if save_feature_method[-1] == '/' else save_feature_method
|
||||
save_feature_method = os.path.basename(save_feature_method)
|
||||
last_model_dir = os.path.join(save_model_path,
|
||||
f'{configs.model_conf.model}_{save_feature_method}',
|
||||
'last_model')
|
||||
if resume_model is not None or (os.path.exists(os.path.join(last_model_dir, 'model.pth'))
|
||||
and os.path.exists(os.path.join(last_model_dir, 'optimizer.pth'))):
|
||||
if resume_model is not None:
|
||||
last_epoch1, accuracy1 = load_model(resume_model)
|
||||
else:
|
||||
try:
|
||||
# 自动获取最新保存的模型
|
||||
last_epoch1, accuracy1 = load_model(last_model_dir)
|
||||
except Exception as e:
|
||||
logger.warning(f'尝试自动恢复最新模型失败,错误信息:{e}')
|
||||
return model, optimizer, amp_scaler, scheduler, last_epoch1, accuracy1
|
||||
|
||||
|
||||
# 保存模型
|
||||
def save_checkpoint(configs, model, optimizer, amp_scaler, save_model_path, epoch_id,
|
||||
accuracy=0., best_model=False):
|
||||
"""保存模型
|
||||
|
||||
:param configs: 配置信息
|
||||
:param model: 使用的模型
|
||||
:param optimizer: 使用的优化方法
|
||||
:param amp_scaler: 使用的自动混合精度
|
||||
:param save_model_path: 模型保存路径
|
||||
:param epoch_id: 当前epoch
|
||||
:param accuracy: 当前准确率
|
||||
:param best_model: 是否为最佳模型
|
||||
"""
|
||||
if isinstance(model, torch.nn.parallel.DistributedDataParallel):
|
||||
state_dict = model.module.state_dict()
|
||||
else:
|
||||
state_dict = model.state_dict()
|
||||
# 保存模型的路径
|
||||
save_feature_method = configs.preprocess_conf.feature_method
|
||||
if configs.preprocess_conf.get('use_hf_model', False):
|
||||
save_feature_method = save_feature_method[:-1] if save_feature_method[-1] == '/' else save_feature_method
|
||||
save_feature_method = os.path.basename(save_feature_method)
|
||||
if best_model:
|
||||
model_path = os.path.join(save_model_path,
|
||||
f'{configs.model_conf.model}_{save_feature_method}', 'best_model')
|
||||
else:
|
||||
model_path = os.path.join(save_model_path,
|
||||
f'{configs.model_conf.model}_{save_feature_method}', 'epoch_{}'.format(epoch_id))
|
||||
os.makedirs(model_path, exist_ok=True)
|
||||
# 保存模型参数
|
||||
torch.save(optimizer.state_dict(), os.path.join(model_path, 'optimizer.pth'))
|
||||
torch.save(state_dict, os.path.join(model_path, 'model.pth'))
|
||||
# 自动混合精度参数
|
||||
if amp_scaler is not None:
|
||||
torch.save(amp_scaler.state_dict(), os.path.join(model_path, 'scaler.pth'))
|
||||
with open(os.path.join(model_path, 'model.state'), 'w', encoding='utf-8') as f:
|
||||
data = {"last_epoch": epoch_id, "accuracy": accuracy, "version": __version__,
|
||||
"model": configs.model_conf.model, "feature_method": save_feature_method}
|
||||
f.write(json.dumps(data, indent=4, ensure_ascii=False))
|
||||
if not best_model:
|
||||
last_model_path = os.path.join(save_model_path,
|
||||
f'{configs.model_conf.model}_{save_feature_method}', 'last_model')
|
||||
shutil.rmtree(last_model_path, ignore_errors=True)
|
||||
shutil.copytree(model_path, last_model_path)
|
||||
# 删除旧的模型
|
||||
old_model_path = os.path.join(save_model_path,
|
||||
f'{configs.model_conf.model}_{save_feature_method}',
|
||||
'epoch_{}'.format(epoch_id - 3))
|
||||
if os.path.exists(old_model_path):
|
||||
shutil.rmtree(old_model_path)
|
||||
logger.info('已保存模型:{}'.format(model_path))
|
||||
@ -0,0 +1,14 @@
|
||||
import time
|
||||
|
||||
from macls.utils.record import RecordAudio
|
||||
|
||||
s = input('请输入你计划录音多少秒:')
|
||||
record_seconds = int(s)
|
||||
save_path = "dataset/save_audio/%s.wav" % str(int(time.time()*1000))
|
||||
|
||||
record_audio = RecordAudio()
|
||||
input(f"按下回车键开机录音,录音{record_seconds}秒中:")
|
||||
record_audio.record(record_seconds=record_seconds,
|
||||
save_path=save_path)
|
||||
|
||||
print('文件保存在:%s' % save_path)
|
||||
@ -0,0 +1,17 @@
|
||||
numpy>=1.19.2
|
||||
scipy>=1.6.3
|
||||
librosa>=0.9.1
|
||||
soundfile>=0.12.1
|
||||
soundcard>=0.4.2
|
||||
resampy>=0.2.2
|
||||
numba>=0.53.0
|
||||
pydub~=0.25.1
|
||||
matplotlib>=3.5.2
|
||||
pillow>=10.3.0
|
||||
tqdm>=4.66.3
|
||||
visualdl==2.5.3
|
||||
pyyaml>=5.4.1
|
||||
scikit-learn>=1.0.2
|
||||
torchinfo>=1.7.2
|
||||
loguru>=0.7.2
|
||||
yeaudio>=0.0.7
|
||||
@ -0,0 +1,54 @@
|
||||
import shutil
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
import macls
|
||||
|
||||
VERSION = macls.__version__
|
||||
|
||||
# 复制配置文件到项目目录下
|
||||
shutil.rmtree('./macls/configs/', ignore_errors=True)
|
||||
shutil.copytree('./configs/', './macls/configs/')
|
||||
|
||||
|
||||
def readme():
|
||||
with open('README.md', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
return content
|
||||
|
||||
|
||||
def parse_requirements():
|
||||
with open('./requirements.txt', encoding="utf-8") as f:
|
||||
requirements = f.readlines()
|
||||
return requirements
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
setup(
|
||||
name='macls',
|
||||
packages=find_packages(),
|
||||
package_data={'': ['configs/*']},
|
||||
author='yeyupiaoling',
|
||||
version=VERSION,
|
||||
install_requires=parse_requirements(),
|
||||
description='Audio Classification toolkit on Pytorch',
|
||||
long_description=readme(),
|
||||
long_description_content_type='text/markdown',
|
||||
url='https://github.com/yeyupiaoling/AudioClassification-Pytorch',
|
||||
download_url='https://github.com/yeyupiaoling/AudioClassification-Pytorch.git',
|
||||
keywords=['audio', 'pytorch'],
|
||||
classifiers=[
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: OS Independent',
|
||||
'Natural Language :: Chinese (Simplified)',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9', 'Topic :: Utilities'
|
||||
],
|
||||
license='Apache License 2.0',
|
||||
ext_modules=[])
|
||||
shutil.rmtree('./macls/configs/', ignore_errors=True)
|
||||
@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
download_dir=dataset/language
|
||||
|
||||
|
||||
[ ! -d ${download_dir} ] && mkdir -p ${download_dir}
|
||||
|
||||
if [ ! -f ${download_dir}/test.tar.gz ]; then
|
||||
echo "准备下载测试集"
|
||||
wget --no-check-certificate https://speech-lab-share-data.oss-cn-shanghai.aliyuncs.com/3D-Speaker/test.tar.gz -P ${download_dir}
|
||||
md5=$(md5sum ${download_dir}/test.tar.gz | awk '{print $1}')
|
||||
[ $md5 != "45972606dd10d3f7c1c31f27acdfbed7" ] && echo "Wrong md5sum of 3dspeaker test.tar.gz" && exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f ${download_dir}/train.tar.gz ]; then
|
||||
echo "准备下载训练集"
|
||||
wget --no-check-certificate https://speech-lab-share-data.oss-cn-shanghai.aliyuncs.com/3D-Speaker/train.tar.gz -P ${download_dir}
|
||||
md5=$(md5sum ${download_dir}/train.tar.gz | awk '{print $1}')
|
||||
[ $md5 != "c2cea55fd22a2b867d295fb35a2d3340" ] && echo "Wrong md5sum of 3dspeaker train.tar.gz" && exit 1
|
||||
fi
|
||||
|
||||
echo "下载完成!"
|
||||
|
||||
echo "准备解压"
|
||||
|
||||
tar -zxvf ${download_dir}/train.tar.gz -C ${rawdata_dir}/
|
||||
tar -xzvf ${download_dir}/test.tar.gz -C ${rawdata_dir}/
|
||||
|
||||
echo "解压完成!"
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,35 @@
|
||||
[NETWORK]
|
||||
host = 0.0.0.0
|
||||
port_audio = 12346
|
||||
port_cmd = 12347
|
||||
port_location = 12348
|
||||
timeout = 30.0
|
||||
buffer_size = 4096
|
||||
|
||||
[AUDIO]
|
||||
sample_rate = 16000
|
||||
channels = 1
|
||||
chunk_size = 1024
|
||||
format = int16
|
||||
|
||||
[RECOGNITION]
|
||||
gunshot_threshold = 0.7
|
||||
recognition_interval = 3.0
|
||||
configs_path = audio-classification/configs/cam++.yml
|
||||
model_path = audio-classification/models/CAMPPlus_Fbank/best_model/
|
||||
|
||||
[VISUALIZATION]
|
||||
plot_interval_ms = 100
|
||||
plot_range = 15.0
|
||||
point_size = 200
|
||||
max_history_points = 100
|
||||
|
||||
[KALMAN]
|
||||
q_x = 5.0
|
||||
r_x = 0.01
|
||||
q_y = 5.0
|
||||
r_y = 0.01
|
||||
q_strength = 5.0
|
||||
r_strength = 0.01
|
||||
q_angle = 5.0
|
||||
r_angle = 0.01
|
||||
@ -0,0 +1,52 @@
|
||||
# Vue.js 项目的 .gitignore 文件
|
||||
|
||||
# 依赖目录
|
||||
node_modules/
|
||||
|
||||
# 构建输出目录
|
||||
/dist
|
||||
/build
|
||||
|
||||
# 本地环境配置文件
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# 日志文件
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# 编辑器目录和文件
|
||||
.idea/
|
||||
.vscode/
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
# 系统文件
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# 测试覆盖率报告
|
||||
/coverage
|
||||
|
||||
# 特定于 Vue CLI 的文件
|
||||
.history/
|
||||
.firebase/
|
||||
.firebase.json
|
||||
.firebaserc
|
||||
|
||||
# 缓存目录
|
||||
.npm/
|
||||
.eslintcache
|
||||
.stylelintcache
|
||||
.history/
|
||||
.cache/
|
||||
|
||||
# 临时文件
|
||||
*.tmp
|
||||
*.temp
|
||||
*.bak
|
||||
@ -0,0 +1,38 @@
|
||||
# 声源定位系统前端
|
||||
|
||||
基于 Vue.js 和 ECharts 实现的声源定位可视化系统,与 Flask 后端通信获取实时声源数据。
|
||||
|
||||
## 功能特点
|
||||
|
||||
- 实时显示声源位置 (X, Y 坐标)
|
||||
- 可视化声源强度和方向
|
||||
- 支持开始/停止监听控制
|
||||
- 专业企业级 UI 设计
|
||||
|
||||
## 项目设置
|
||||
|
||||
### 安装依赖
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
### 开发环境运行
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
### 生产环境构建
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
## 配置说明
|
||||
|
||||
后端 API 地址可在 `App.vue` 中的 `API_BASE_URL` 变量修改。
|
||||
|
||||
## 使用方法
|
||||
|
||||
1. 确保 Flask 后端已启动并在指定端口运行
|
||||
2. 启动前端应用
|
||||
3. 点击"开始监听"按钮开始获取实时数据
|
||||
4. 声源位置、强度和方向将在可视化图表中实时显示
|
||||
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>声源定位系统</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "sound-vue-frontend",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.3.4",
|
||||
"core-js": "^3.8.3",
|
||||
"echarts": "^5.4.1",
|
||||
"element-plus": "^2.3.0",
|
||||
"vue": "^3.2.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~5.0.0",
|
||||
"@vue/cli-plugin-eslint": "~5.0.0",
|
||||
"@vue/cli-service": "~5.0.0",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-plugin-vue": "^8.0.3"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/vue3-essential",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020
|
||||
},
|
||||
"rules": {}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
/* 基础样式重置 */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
color: #2c3e50;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
#app {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
// 声源数据接口服务
|
||||
import axios from 'axios';
|
||||
|
||||
const API_BASE_URL = 'http://127.0.0.1:5000'; // 根据实际后端地址进行配置
|
||||
|
||||
export default {
|
||||
// 获取最新声源数据
|
||||
getSourceData() {
|
||||
return axios.get(`${API_BASE_URL}/data`);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,8 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import ElementPlus from 'element-plus'
|
||||
import 'element-plus/dist/index.css'
|
||||
|
||||
const app = createApp(App)
|
||||
app.use(ElementPlus)
|
||||
app.mount('#app')
|
||||
@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
devServer: {
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:5000',
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
'^/api': ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,423 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2016 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "py/objlist.h"
|
||||
#include "py/objstringio.h"
|
||||
#include "py/parsenum.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
#include "py/objmodule.h"
|
||||
#include "py/objstringio.h"
|
||||
#include "mphalport.h"
|
||||
#include "vfs_internal.h"
|
||||
|
||||
#include "Maix_config.h"
|
||||
|
||||
// static void unit_test_json_config();
|
||||
|
||||
mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, size_t *cur)
|
||||
{
|
||||
size_t max = dict->map.alloc;
|
||||
mp_map_t *map = &dict->map;
|
||||
|
||||
for (size_t i = *cur; i < max; i++)
|
||||
{
|
||||
if (mp_map_slot_is_filled(map, i))
|
||||
{
|
||||
*cur = i + 1;
|
||||
return &(map->table[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define MAIX_CONFIG_PATH "/flash/config.json"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t cache;
|
||||
mp_obj_t args[3];
|
||||
} maix_config_t;
|
||||
|
||||
static maix_config_t *config_obj = NULL;
|
||||
|
||||
static mp_obj_t maix_config_cache()
|
||||
{
|
||||
// printf("%s\r\n", __func__);
|
||||
typedef struct
|
||||
{
|
||||
mp_obj_base_t base;
|
||||
} fs_info_t;
|
||||
|
||||
int err = 0;
|
||||
fs_info_t *cfg = vfs_internal_open(MAIX_CONFIG_PATH, "rb", &err);
|
||||
if (err != 0)
|
||||
{
|
||||
// printf("no config time:%ld\r\n", systick_current_millis());
|
||||
}
|
||||
else
|
||||
{
|
||||
// printf("exist config time:%ld\r\n", systick_current_millis());
|
||||
config_obj->args[2] = MP_OBJ_FROM_PTR(&(cfg->base));
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0)
|
||||
{
|
||||
config_obj->cache = mp_call_method_n_kw(1, 0, config_obj->args);
|
||||
nlr_pop();
|
||||
vfs_internal_close(cfg, &err);
|
||||
return mp_const_true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
|
||||
}
|
||||
vfs_internal_close(cfg, &err);
|
||||
}
|
||||
return mp_const_false;
|
||||
}
|
||||
|
||||
mp_obj_t maix_config_get_value(mp_obj_t key, mp_obj_t def_value)
|
||||
{
|
||||
// printf("%s\r\n", __func__);
|
||||
if (config_obj != NULL)
|
||||
{
|
||||
if (false == mp_obj_is_type(config_obj->cache, &mp_type_dict))
|
||||
{
|
||||
// maybe gc.collect()
|
||||
if (mp_const_false == maix_config_cache())
|
||||
{
|
||||
return def_value;
|
||||
}
|
||||
}
|
||||
// mp_printf(&mp_plat_print, "print(config_obj->cache)\r\n");
|
||||
// mp_obj_print_helper(&mp_plat_print, config_obj->cache, PRINT_STR);
|
||||
// mp_printf(&mp_plat_print, "\r\n");
|
||||
// mp_check_self(mp_obj_is_dict_type(config_obj->cache));
|
||||
mp_obj_dict_t *self = MP_OBJ_TO_PTR(config_obj->cache);
|
||||
mp_map_elem_t *elem = mp_map_lookup(&self->map, key, MP_MAP_LOOKUP);
|
||||
if (elem == NULL || elem->value == MP_OBJ_NULL)
|
||||
{
|
||||
return def_value; // not exist
|
||||
}
|
||||
else
|
||||
{
|
||||
return elem->value;
|
||||
}
|
||||
}
|
||||
return def_value;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(maix_config_get_value_obj, maix_config_get_value);
|
||||
|
||||
mp_obj_t maix_config_init()
|
||||
{
|
||||
// printf("%s\r\n", __func__);
|
||||
// unit_test_json_config();
|
||||
static maix_config_t tmp;
|
||||
mp_obj_t module_obj = mp_module_get(MP_QSTR_ujson);
|
||||
if (module_obj != MP_OBJ_NULL)
|
||||
{
|
||||
// mp_printf(&mp_plat_print, "import josn\r\n");
|
||||
mp_load_method_maybe(module_obj, MP_QSTR_load, tmp.args);
|
||||
if (tmp.args[0] != MP_OBJ_NULL)
|
||||
{
|
||||
config_obj = &tmp;
|
||||
return maix_config_cache();
|
||||
// return mp_const_true;
|
||||
}
|
||||
}
|
||||
mp_printf(&mp_plat_print, "[%s]|(%s)\r\n", __func__, "fail");
|
||||
return mp_const_false;
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(maix_config_init_obj, maix_config_init);
|
||||
|
||||
static const mp_map_elem_t locals_dict_table[] = {
|
||||
{MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_config)},
|
||||
{MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&maix_config_init_obj)},
|
||||
{MP_ROM_QSTR(MP_QSTR_get_value), MP_ROM_PTR(&maix_config_get_value_obj)},
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(locals_dict, locals_dict_table);
|
||||
|
||||
const mp_obj_type_t Maix_config_type = {
|
||||
.base = {&mp_type_type},
|
||||
.name = MP_QSTR_config,
|
||||
.locals_dict = (mp_obj_dict_t *)&locals_dict};
|
||||
|
||||
#ifdef UNIT_TEST
|
||||
|
||||
/*
|
||||
{
|
||||
"config_name": "config.json",
|
||||
"lcd":{
|
||||
"RST_IO":16,
|
||||
"DCX_IO":32
|
||||
},
|
||||
"freq_cpu": 416000000,
|
||||
"freq_pll1": 400000000,
|
||||
"kpu_div": 1
|
||||
}
|
||||
*/
|
||||
|
||||
static void unit_test_json_config()
|
||||
{
|
||||
// unit_test get string
|
||||
{
|
||||
const char key[] = "config_name";
|
||||
mp_obj_t tmp = maix_config_get_value(mp_obj_new_str(key, sizeof(key) - 1), mp_obj_new_str("None Cfg", 8));
|
||||
if (mp_obj_is_str(tmp))
|
||||
{
|
||||
const char *value = mp_obj_str_get_str(tmp);
|
||||
mp_printf(&mp_plat_print, "%s %s\r\n", key, value);
|
||||
}
|
||||
}
|
||||
|
||||
// get lcd dict key-value
|
||||
{
|
||||
const char key[] = "lcd";
|
||||
mp_obj_t tmp = maix_config_get_value(mp_obj_new_str(key, sizeof(key) - 1), mp_obj_new_dict(0));
|
||||
if (mp_obj_is_type(tmp, &mp_type_dict))
|
||||
{
|
||||
mp_obj_dict_t *self = MP_OBJ_TO_PTR(tmp);
|
||||
size_t cur = 0;
|
||||
mp_map_elem_t *next = NULL;
|
||||
bool first = true;
|
||||
while ((next = dict_iter_next(self, &cur)) != NULL)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
mp_print_str(&mp_plat_print, ", ");
|
||||
}
|
||||
first = false;
|
||||
mp_obj_print_helper(&mp_plat_print, next->key, PRINT_STR);
|
||||
mp_print_str(&mp_plat_print, ": ");
|
||||
mp_obj_print_helper(&mp_plat_print, next->value, PRINT_STR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void unit_test_json_config()
|
||||
{
|
||||
mp_obj_t module_obj = mp_module_get(MP_QSTR_ujson);
|
||||
if (module_obj != MP_OBJ_NULL)
|
||||
{
|
||||
mp_printf(&mp_plat_print, "import josn\r\n");
|
||||
mp_obj_t dest[3];
|
||||
mp_load_method_maybe(module_obj, MP_QSTR_loads, dest);
|
||||
if (dest[0] != MP_OBJ_NULL)
|
||||
{
|
||||
const char json[] = "{\"a\":1,\"b\":2,\"c\":3,\"d\":4,\"e\":\"helloworld\"}";
|
||||
mp_printf(&mp_plat_print, "nresult = josn.loads(%s)\r\n", json);
|
||||
dest[2] = mp_obj_new_str(json, sizeof(json) - 1);
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0)
|
||||
{
|
||||
mp_obj_t result = mp_call_method_n_kw(1, 0, dest);
|
||||
mp_printf(&mp_plat_print, "print(result)\r\n");
|
||||
mp_obj_print_helper(&mp_plat_print, result, PRINT_STR);
|
||||
mp_printf(&mp_plat_print, "\r\n");
|
||||
const char goal[] = "e";
|
||||
//mp_check_self(mp_obj_is_dict_type(result));
|
||||
mp_obj_dict_t *self = MP_OBJ_TO_PTR(result);
|
||||
mp_map_elem_t *elem = mp_map_lookup(&self->map, mp_obj_new_str(goal, sizeof(goal) - 1), MP_MAP_LOOKUP);
|
||||
mp_obj_t value;
|
||||
if (elem == NULL || elem->value == MP_OBJ_NULL)
|
||||
{
|
||||
// not exist
|
||||
}
|
||||
else
|
||||
{
|
||||
value = elem->value;
|
||||
//mp_check_self(mp_obj_is_str_type(value));
|
||||
mp_printf(&mp_plat_print, "print(result.get('%s'))\r\n", goal);
|
||||
mp_obj_print_helper(&mp_plat_print, value, PRINT_STR);
|
||||
mp_printf(&mp_plat_print, "\r\n");
|
||||
}
|
||||
nlr_pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
|
||||
}
|
||||
}
|
||||
mp_load_method_maybe(module_obj, MP_QSTR_load, dest);
|
||||
if (dest[0] != MP_OBJ_NULL)
|
||||
{
|
||||
const char json[] = "{\"a\":1,\"b\":2,\"c\":3,\"d\":4,\"e\":\"helloworld\"}";
|
||||
mp_printf(&mp_plat_print, "nresult = josn.load(%s)\r\n", json);
|
||||
mp_obj_t obj = mp_obj_new_str(json, sizeof(json) - 1);
|
||||
size_t len;
|
||||
const char *buf = mp_obj_str_get_data(obj, &len);
|
||||
vstr_t vstr = {len, len, (char *)buf, true};
|
||||
mp_obj_stringio_t sio = {{&mp_type_stringio}, &vstr, 0, MP_OBJ_NULL};
|
||||
dest[2] = MP_OBJ_FROM_PTR(&sio);
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0)
|
||||
{
|
||||
mp_obj_t result = mp_call_method_n_kw(1, 0, dest);
|
||||
mp_printf(&mp_plat_print, "print(result)\r\n");
|
||||
mp_obj_print_helper(&mp_plat_print, result, PRINT_STR);
|
||||
mp_printf(&mp_plat_print, "\r\n");
|
||||
const char goal[] = "a";
|
||||
//mp_check_self(mp_obj_is_dict_type(result));
|
||||
mp_obj_dict_t *self = MP_OBJ_TO_PTR(result);
|
||||
mp_map_elem_t *elem = mp_map_lookup(&self->map, mp_obj_new_str(goal, sizeof(goal) - 1), MP_MAP_LOOKUP);
|
||||
mp_obj_t value;
|
||||
if (elem == NULL || elem->value == MP_OBJ_NULL)
|
||||
{
|
||||
// not exist
|
||||
}
|
||||
else
|
||||
{
|
||||
value = elem->value;
|
||||
//mp_check_self(mp_obj_is_str_type(value));
|
||||
mp_printf(&mp_plat_print, "print(result.get('%s'))\r\n", goal);
|
||||
mp_obj_print_helper(&mp_plat_print, value, PRINT_STR);
|
||||
mp_printf(&mp_plat_print, "\r\n");
|
||||
}
|
||||
nlr_pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
|
||||
}
|
||||
}
|
||||
typedef struct
|
||||
{
|
||||
mp_obj_base_t base;
|
||||
} fs_info_t;
|
||||
{
|
||||
|
||||
int err = 0;
|
||||
fs_info_t *cfg = vfs_internal_open("/flash/config.json", "rb", &err);
|
||||
if (err != 0)
|
||||
{
|
||||
printf("no config time:%ld\r\n", systick_current_millis());
|
||||
}
|
||||
else
|
||||
{
|
||||
// mp_stream_p_t* stream = (mp_stream_p_t*)cfg->base.type->protocol;
|
||||
printf("exist config time:%ld\r\n", systick_current_millis());
|
||||
mp_load_method_maybe(module_obj, MP_QSTR_load, dest);
|
||||
if (dest[0] != MP_OBJ_NULL)
|
||||
{
|
||||
dest[2] = MP_OBJ_FROM_PTR(&(cfg->base));
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0)
|
||||
{
|
||||
mp_obj_t result = mp_call_method_n_kw(1, 0, dest);
|
||||
mp_printf(&mp_plat_print, "print(result)\r\n");
|
||||
mp_obj_print_helper(&mp_plat_print, result, PRINT_STR);
|
||||
mp_printf(&mp_plat_print, "\r\n");
|
||||
const char goal[] = "a";
|
||||
//mp_check_self(mp_obj_is_dict_type(result));
|
||||
mp_obj_dict_t *self = MP_OBJ_TO_PTR(result);
|
||||
mp_map_elem_t *elem = mp_map_lookup(&self->map, mp_obj_new_str(goal, sizeof(goal) - 1), MP_MAP_LOOKUP);
|
||||
mp_obj_t value;
|
||||
if (elem == NULL || elem->value == MP_OBJ_NULL)
|
||||
{
|
||||
// not exist
|
||||
}
|
||||
else
|
||||
{
|
||||
value = elem->value;
|
||||
//mp_check_self(mp_obj_is_str_type(value));
|
||||
mp_printf(&mp_plat_print, "print(result.get('%s'))\r\n", goal);
|
||||
mp_obj_print_helper(&mp_plat_print, value, PRINT_STR);
|
||||
mp_printf(&mp_plat_print, "\r\n");
|
||||
}
|
||||
nlr_pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
|
||||
}
|
||||
|
||||
vfs_internal_close(cfg, &err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
int err = 0;
|
||||
fs_info_t *cfg = vfs_internal_open("/flash/config.json", "rb", &err);
|
||||
if (err != 0)
|
||||
{
|
||||
printf("no config time:%ld\r\n", systick_current_millis());
|
||||
}
|
||||
else
|
||||
{
|
||||
// mp_stream_p_t* stream = (mp_stream_p_t*)cfg->base.type->protocol;
|
||||
printf("exist config time:%ld\r\n", systick_current_millis());
|
||||
mp_load_method_maybe(module_obj, MP_QSTR_load, dest);
|
||||
if (dest[0] != MP_OBJ_NULL)
|
||||
{
|
||||
dest[2] = MP_OBJ_FROM_PTR(&(cfg->base));
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0)
|
||||
{
|
||||
mp_obj_t result = mp_call_method_n_kw(1, 0, dest);
|
||||
mp_printf(&mp_plat_print, "print(result)\r\n");
|
||||
mp_obj_print_helper(&mp_plat_print, result, PRINT_STR);
|
||||
mp_printf(&mp_plat_print, "\r\n");
|
||||
const char goal[] = "e";
|
||||
//mp_check_self(mp_obj_is_dict_type(result));
|
||||
mp_obj_dict_t *self = MP_OBJ_TO_PTR(result);
|
||||
mp_map_elem_t *elem = mp_map_lookup(&self->map, mp_obj_new_str(goal, sizeof(goal) - 1), MP_MAP_LOOKUP);
|
||||
mp_obj_t value;
|
||||
if (elem == NULL || elem->value == MP_OBJ_NULL)
|
||||
{
|
||||
// not exist
|
||||
}
|
||||
else
|
||||
{
|
||||
value = elem->value;
|
||||
//mp_check_self(mp_obj_is_str_type(value));
|
||||
mp_printf(&mp_plat_print, "print(result.get('%s'))\r\n", goal);
|
||||
mp_obj_print_helper(&mp_plat_print, value, PRINT_STR);
|
||||
mp_printf(&mp_plat_print, "\r\n");
|
||||
}
|
||||
nlr_pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
|
||||
}
|
||||
|
||||
vfs_internal_close(cfg, &err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright 2019 Sipeed Co.,Ltd.
|
||||
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dmac.h"
|
||||
#include "hal_fft.h"
|
||||
#include "i2s.h"
|
||||
#include "math.h"
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/objarray.h"
|
||||
#include "py/binary.h"
|
||||
#include "mphalport.h"
|
||||
#include "modMaix.h"
|
||||
|
||||
#define MAX_SAMPLE_RATE 65535
|
||||
#define MAX_BUFFER_LEN 1024
|
||||
|
||||
const mp_obj_type_t Maix_fft_type;
|
||||
|
||||
STATIC mp_obj_t Maix_fft_run(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
|
||||
{
|
||||
//----------parse parameter---------------
|
||||
enum{ARG_byte,
|
||||
ARG_points,
|
||||
ARG_shift,
|
||||
ARG_direction,
|
||||
};
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_byte, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_points, MP_ARG_INT, {.u_int = 64} },
|
||||
{ MP_QSTR_shift, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_direction, MP_ARG_INT, {.u_int = FFT_DIR_FORWARD} },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
uint32_t points = args[ARG_points].u_int;
|
||||
uint32_t shift = args[ARG_shift].u_int;
|
||||
uint32_t direction = args[ARG_direction].u_int;
|
||||
|
||||
if(points != 64 && points != 128 && points != 256 && points != 512)
|
||||
{
|
||||
mp_raise_ValueError("[MAIXPY]FFT:invalid points");
|
||||
}
|
||||
|
||||
uint32_t byte_len = 0;
|
||||
uint32_t* byte_addr = NULL;
|
||||
|
||||
if( args[ARG_byte].u_obj != mp_const_none)
|
||||
{
|
||||
mp_obj_t byte = args[ARG_byte].u_obj;
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(byte, &bufinfo, MP_BUFFER_READ);
|
||||
byte_len = bufinfo.len;
|
||||
byte_addr = (uint32_t*)bufinfo.buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
mp_raise_ValueError("[MAIXPY]FFT:invalid byte");
|
||||
}
|
||||
if(byte_len % 4 != 0)
|
||||
{
|
||||
mp_raise_ValueError("[MAIXPY]FFT:Buffer length must be a multiple of 4");
|
||||
}
|
||||
// how to get the length of i2s buffer?
|
||||
if(byte_len < points * 4)
|
||||
{
|
||||
mp_printf(&mp_plat_print, "[MAIXPY]FFT:Zero padding\n");
|
||||
memset(byte_addr+byte_len, 0, points * 4 - byte_len );//Zero padding
|
||||
}
|
||||
|
||||
//------------------get data----------------------
|
||||
uint64_t* buffer_input = (uint64_t*)m_new(uint64_t, points);//m_new
|
||||
uint64_t* buffer_output = (uint64_t*)m_new(uint64_t ,points);//m_new
|
||||
fft_data_t * input_data = NULL;
|
||||
fft_data_t * output_data = NULL;
|
||||
for(int i = 0; i < points / 2; ++i)
|
||||
{
|
||||
input_data = (fft_data_t *)&buffer_input[i];
|
||||
input_data->R1 = byte_addr[2*i];
|
||||
input_data->I1 = 0;
|
||||
input_data->R2 = byte_addr[2*i+1];
|
||||
input_data->I2 = 0;
|
||||
}
|
||||
//run fft
|
||||
fft_complex_uint16_dma(DMAC_CHANNEL3, DMAC_CHANNEL4,shift,direction,buffer_input,points,buffer_output);
|
||||
//return a list
|
||||
mp_obj_list_t* ret_list = (mp_obj_list_t*)m_new(mp_obj_list_t,sizeof(mp_obj_list_t));//m_new
|
||||
mp_obj_list_init(ret_list, 0);
|
||||
mp_obj_t tuple_1[2];
|
||||
mp_obj_t tuple_2[2];
|
||||
for (int i = 0; i < points / 2; i++)
|
||||
{
|
||||
output_data = (fft_data_t*)&buffer_output[i];
|
||||
tuple_1[0] = mp_obj_new_int(output_data->R1);
|
||||
tuple_1[1] = mp_obj_new_int(output_data->I1);
|
||||
mp_obj_list_append(ret_list, mp_obj_new_tuple(MP_ARRAY_SIZE(tuple_1), tuple_1));
|
||||
|
||||
tuple_2[0] = mp_obj_new_int(output_data->R2);
|
||||
tuple_2[1] = mp_obj_new_int(output_data->I2);
|
||||
mp_obj_list_append(ret_list, mp_obj_new_tuple(MP_ARRAY_SIZE(tuple_2), tuple_2));
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(ret_list);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(Maix_fft_run_obj,1, Maix_fft_run);
|
||||
|
||||
STATIC mp_obj_t Maix_fft_freq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
|
||||
{
|
||||
//----------parse parameter---------------
|
||||
enum{ARG_points,
|
||||
ARG_sample_rate,
|
||||
};
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_points, MP_ARG_INT, {.u_int = 64} },
|
||||
{ MP_QSTR_sample_rate, MP_ARG_INT, {.u_int = 16000} },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
uint32_t sample_rate = args[ARG_sample_rate].u_int;
|
||||
uint32_t points = args[ARG_points].u_int;
|
||||
|
||||
uint32_t step = sample_rate/points;
|
||||
mp_obj_list_t* ret_list = (mp_obj_list_t*)m_new(mp_obj_list_t,sizeof(mp_obj_list_t));//m_new
|
||||
mp_obj_list_init(ret_list, 0);
|
||||
for(int i = 0; i < points; i++)
|
||||
{
|
||||
mp_obj_list_append(ret_list, mp_obj_new_int(step * i));
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(ret_list);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(Maix_fft_freq_obj,1, Maix_fft_freq);
|
||||
|
||||
|
||||
STATIC mp_obj_t Maix_fft_amplitude(const mp_obj_t list_obj)
|
||||
{
|
||||
|
||||
if(&mp_type_list != mp_obj_get_type(list_obj))
|
||||
{
|
||||
mp_raise_ValueError("[MAIXPY]FFT:obj is not a list");
|
||||
}
|
||||
mp_obj_list_t* ret_list = (mp_obj_list_t*)m_new(mp_obj_list_t,sizeof(mp_obj_list_t));//m_new
|
||||
mp_obj_list_init(ret_list, 0);
|
||||
//----------------------------------
|
||||
mp_obj_list_t* list = MP_OBJ_TO_PTR(list_obj);
|
||||
uint32_t index = 0;
|
||||
mp_obj_t list_iter;
|
||||
mp_obj_tuple_t* tuple;
|
||||
for(index = 0; index < list->len; index++)
|
||||
{
|
||||
list_iter = list->items[index];
|
||||
tuple = MP_OBJ_FROM_PTR(list_iter);
|
||||
uint32_t r_val = MP_OBJ_SMALL_INT_VALUE(tuple->items[0]);
|
||||
uint32_t i_val = MP_OBJ_SMALL_INT_VALUE(tuple->items[1]);
|
||||
uint32_t amplitude = sqrt(r_val * r_val + i_val * i_val);
|
||||
//Convert to power
|
||||
uint32_t hard_power = 2*amplitude/list->len;
|
||||
mp_obj_list_append(ret_list,mp_obj_new_int(hard_power));
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(ret_list);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(Maix_fft_amplitude_obj, Maix_fft_amplitude);
|
||||
|
||||
STATIC const mp_rom_map_elem_t Maix_fft_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_run), MP_ROM_PTR(&Maix_fft_run_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&Maix_fft_freq_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_amplitude), MP_ROM_PTR(&Maix_fft_amplitude_obj) },
|
||||
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(Maix_fft_dict, Maix_fft_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t Maix_fft_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_FFT,
|
||||
.locals_dict = (mp_obj_dict_t*)&Maix_fft_dict,
|
||||
};
|
||||
@ -0,0 +1,395 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "py/mphal.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/objtype.h"
|
||||
#include "py/objstr.h"
|
||||
#include "py/objint.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "fpioa.h"
|
||||
#include "fpioa_des.h"
|
||||
|
||||
/*Please don't modify this macro*/
|
||||
#define DES_SPACE_NUM(str) (sizeof(" ")-sizeof(" "))-strlen(str)
|
||||
#define FUN_SPACE_NUM(str) (sizeof(" ")-sizeof(" "))-strlen(str)
|
||||
|
||||
typedef struct _Maix_fpioa_obj_t {
|
||||
mp_obj_base_t base;
|
||||
}Maix_fpioa_obj_t;
|
||||
|
||||
const mp_obj_type_t Maix_fpioa_type;
|
||||
|
||||
|
||||
STATIC mp_obj_t Maix_set_function(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum {
|
||||
ARG_pin,
|
||||
ARG_func,
|
||||
ARG_set_sl,
|
||||
ARG_set_st,
|
||||
ARG_set_io_driving
|
||||
};
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_pin, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_func, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_set_sl, MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_set_st, MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_set_io_driving, MP_ARG_INT, {.u_int = -1} },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args-1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
uint16_t pin_num = args[ARG_pin].u_int;
|
||||
fpioa_function_t func_num = args[ARG_func].u_int;
|
||||
int16_t set_sl = args[ARG_set_sl].u_int;
|
||||
int16_t set_st = args[ARG_set_st].u_int;
|
||||
int16_t set_io_driving = args[ARG_set_io_driving].u_int;
|
||||
|
||||
if(pin_num > FPIOA_NUM_IO)
|
||||
mp_raise_ValueError("Don't have this Pin");
|
||||
|
||||
if(func_num < 0 || func_num > USABLE_FUNC_NUM)
|
||||
mp_raise_ValueError("This function is invalid");
|
||||
|
||||
if(0 != fpioa_set_function(pin_num,func_num))
|
||||
{
|
||||
mp_printf(&mp_plat_print, "[Maix]:Opps!Can not set fpioa\n");
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
|
||||
if (-1 != set_sl) {
|
||||
fpioa_set_sl(pin_num, set_sl);
|
||||
}
|
||||
|
||||
if (-1 != set_st) {
|
||||
fpioa_set_st(pin_num, set_st);
|
||||
}
|
||||
|
||||
if(set_io_driving > FPIOA_DRIVING_MAX)
|
||||
mp_raise_ValueError("set_io_driving > FPIOA_DRIVING_MAX");
|
||||
|
||||
if (-1 != set_io_driving) {
|
||||
fpioa_set_io_driving(pin_num, set_io_driving);
|
||||
}
|
||||
|
||||
return mp_const_true;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(Maix_set_function_obj, 0,Maix_set_function);
|
||||
|
||||
STATIC mp_obj_t Maix_get_Pin_num(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum {
|
||||
ARG_func,
|
||||
};
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_func, MP_ARG_INT, {.u_int = 0} },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args-1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
fpioa_function_t fun_num = args[ARG_func].u_int;
|
||||
|
||||
if(fun_num < 0 || fun_num > USABLE_FUNC_NUM)
|
||||
mp_raise_ValueError("This function is invalid");
|
||||
|
||||
int Pin_num = fpioa_get_io_by_function(fun_num);
|
||||
|
||||
if(-1 == Pin_num)
|
||||
{
|
||||
return mp_const_none;
|
||||
}
|
||||
return MP_OBJ_NEW_SMALL_INT(Pin_num);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(Maix_get_Pin_num_obj, 0,Maix_get_Pin_num);
|
||||
|
||||
|
||||
STATIC mp_obj_t Maix_fpioa_help(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum {
|
||||
ARG_func,
|
||||
};
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_func, MP_ARG_INT, {.u_int = USABLE_FUNC_NUM} },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args-1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
char* des_space_str = NULL;
|
||||
char* fun_space_str = NULL;
|
||||
if(args[ARG_func].u_int > USABLE_FUNC_NUM)
|
||||
{
|
||||
mp_printf(&mp_plat_print, "No this funciton Description\n");
|
||||
return mp_const_false;
|
||||
}
|
||||
mp_printf(&mp_plat_print, "+-------------------+----------------------------------+\n") ;
|
||||
mp_printf(&mp_plat_print, "| Function | Description |\n") ;
|
||||
mp_printf(&mp_plat_print, "+-------------------+----------------------------------+\n") ;
|
||||
if(args[ARG_func].u_int == USABLE_FUNC_NUM)
|
||||
{
|
||||
|
||||
for(int i = 0;i < USABLE_FUNC_NUM ; i++)
|
||||
{
|
||||
/*malloc memory*/
|
||||
des_space_str = (char*)malloc(DES_SPACE_NUM(func_description[i])+1);
|
||||
fun_space_str = (char*)malloc(FUN_SPACE_NUM( func_name[i])+1);
|
||||
|
||||
memset(des_space_str,' ',DES_SPACE_NUM(func_description[i]));
|
||||
des_space_str[DES_SPACE_NUM(func_description[i])] = '\0';
|
||||
|
||||
memset(fun_space_str,' ',FUN_SPACE_NUM( func_name[i]));
|
||||
fun_space_str[FUN_SPACE_NUM( func_name[i])] = '\0';
|
||||
|
||||
|
||||
mp_printf(&mp_plat_print, "| %s%s| %s%s|\n", func_name[i],fun_space_str,func_description[i],des_space_str) ;
|
||||
free(des_space_str);
|
||||
free(fun_space_str);
|
||||
mp_printf(&mp_plat_print, "+-------------------+----------------------------------+\n") ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
des_space_str = (char*)malloc(DES_SPACE_NUM(func_description[args[ARG_func].u_int])+1);
|
||||
fun_space_str = (char*)malloc(FUN_SPACE_NUM(func_name[args[ARG_func].u_int])+1);
|
||||
|
||||
memset(des_space_str,' ',DES_SPACE_NUM(func_description[args[ARG_func].u_int]));
|
||||
des_space_str[DES_SPACE_NUM(func_description[args[ARG_func].u_int])] = '\0';
|
||||
|
||||
memset(fun_space_str,' ',FUN_SPACE_NUM(func_name[args[ARG_func].u_int]));
|
||||
fun_space_str[FUN_SPACE_NUM(func_name[args[ARG_func].u_int])] = '\0';
|
||||
|
||||
mp_printf(&mp_plat_print, "| %s%s| %s%s|\n", func_name[args[ARG_func].u_int],fun_space_str,func_description[args[ARG_func].u_int],des_space_str) ;
|
||||
free(des_space_str);
|
||||
free(fun_space_str);
|
||||
mp_printf(&mp_plat_print, "+-------------------+----------------------------------+\n") ;
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(Maix_fpioa_help_obj, 0,Maix_fpioa_help);
|
||||
|
||||
STATIC mp_obj_t Maix_fpioa_make_new() {
|
||||
|
||||
Maix_fpioa_obj_t *self = m_new_obj(Maix_fpioa_obj_t);
|
||||
self->base.type = &Maix_fpioa_type;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
STATIC const mp_rom_map_elem_t Maix_fpioa_locals_dict_table[] = {
|
||||
// fpioa methods
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_function), MP_ROM_PTR(&Maix_set_function_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_help), MP_ROM_PTR(&Maix_fpioa_help_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_get_Pin_num), MP_ROM_PTR(&Maix_get_Pin_num_obj) },
|
||||
{MP_ROM_QSTR(MP_QSTR_JTAG_TCLK ), MP_ROM_INT(0 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_JTAG_TDI ), MP_ROM_INT(1 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_JTAG_TMS ), MP_ROM_INT(2 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_JTAG_TDO ), MP_ROM_INT(3 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI0_D0 ), MP_ROM_INT(4 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI0_D1 ), MP_ROM_INT(5 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI0_D2 ), MP_ROM_INT(6 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI0_D3 ), MP_ROM_INT(7 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI0_D4 ), MP_ROM_INT(8 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI0_D5 ), MP_ROM_INT(9 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI0_D6 ), MP_ROM_INT(10 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI0_D7 ), MP_ROM_INT(11 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI0_SS0 ), MP_ROM_INT(12 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI0_SS1 ), MP_ROM_INT(13 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI0_SS2 ), MP_ROM_INT(14 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI0_SS3 ), MP_ROM_INT(15 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI0_ARB ), MP_ROM_INT(16 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI0_SCLK ), MP_ROM_INT(17 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_UARTHS_RX ), MP_ROM_INT(18 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_UARTHS_TX ), MP_ROM_INT(19 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_RESV6 ), MP_ROM_INT(20 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_RESV7 ), MP_ROM_INT(21 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_CLK_SPI1 ), MP_ROM_INT(22 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_CLK_I2C1 ), MP_ROM_INT(23 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS0 ), MP_ROM_INT(24 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS1 ), MP_ROM_INT(25 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS2 ), MP_ROM_INT(26 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS3 ), MP_ROM_INT(27 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS4 ), MP_ROM_INT(28 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS5 ), MP_ROM_INT(29 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS6 ), MP_ROM_INT(30 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS7 ), MP_ROM_INT(31 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS8 ), MP_ROM_INT(32 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS9 ), MP_ROM_INT(33 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS10 ), MP_ROM_INT(34 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS11 ), MP_ROM_INT(35 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS12 ), MP_ROM_INT(36 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS13 ), MP_ROM_INT(37 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS14 ), MP_ROM_INT(38 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS15 ), MP_ROM_INT(39 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS16 ), MP_ROM_INT(40 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS17 ), MP_ROM_INT(41 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS18 ), MP_ROM_INT(42 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS19 ), MP_ROM_INT(43 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS20 ), MP_ROM_INT(44 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS21 ), MP_ROM_INT(45 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS22 ), MP_ROM_INT(46 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS23 ), MP_ROM_INT(47 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS24 ), MP_ROM_INT(48 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS25 ), MP_ROM_INT(49 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS26 ), MP_ROM_INT(50 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS27 ), MP_ROM_INT(51 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS28 ), MP_ROM_INT(52 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS29 ), MP_ROM_INT(53 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS30 ), MP_ROM_INT(54 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIOHS31 ), MP_ROM_INT(55 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIO0 ), MP_ROM_INT(56 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIO1 ), MP_ROM_INT(57 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIO2 ), MP_ROM_INT(58 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIO3 ), MP_ROM_INT(59 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIO4 ), MP_ROM_INT(60 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIO5 ), MP_ROM_INT(61 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIO6 ), MP_ROM_INT(62 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_GPIO7 ), MP_ROM_INT(63 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART1_RX ), MP_ROM_INT(64 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART1_TX ), MP_ROM_INT(65 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART2_RX ), MP_ROM_INT(66 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART2_TX ), MP_ROM_INT(67 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART3_RX ), MP_ROM_INT(68 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART3_TX ), MP_ROM_INT(69 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI1_D0 ), MP_ROM_INT(70 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI1_D1 ), MP_ROM_INT(71 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI1_D2 ), MP_ROM_INT(72 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI1_D3 ), MP_ROM_INT(73 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI1_D4 ), MP_ROM_INT(74 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI1_D5 ), MP_ROM_INT(75 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI1_D6 ), MP_ROM_INT(76 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI1_D7 ), MP_ROM_INT(77 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI1_SS0 ), MP_ROM_INT(78 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI1_SS1 ), MP_ROM_INT(79 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI1_SS2 ), MP_ROM_INT(80 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI1_SS3 ), MP_ROM_INT(81 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI1_ARB ), MP_ROM_INT(82 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI1_SCLK ), MP_ROM_INT(83 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI_SLAVE_D0 ), MP_ROM_INT(84 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI_SLAVE_SS ), MP_ROM_INT(85 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_SPI_SLAVE_SCLK), MP_ROM_INT(86 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S0_MCLK ), MP_ROM_INT(87 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S0_SCLK ), MP_ROM_INT(88 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S0_WS ), MP_ROM_INT(89 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S0_IN_D0 ), MP_ROM_INT(90 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S0_IN_D1 ), MP_ROM_INT(91 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S0_IN_D2 ), MP_ROM_INT(92 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S0_IN_D3 ), MP_ROM_INT(93 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S0_OUT_D0 ), MP_ROM_INT(94 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S0_OUT_D1 ), MP_ROM_INT(95 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S0_OUT_D2 ), MP_ROM_INT(96 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S0_OUT_D3 ), MP_ROM_INT(97 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S1_MCLK ), MP_ROM_INT(98 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S1_SCLK ), MP_ROM_INT(99 )},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S1_WS ), MP_ROM_INT(100)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S1_IN_D0 ), MP_ROM_INT(101)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S1_IN_D1 ), MP_ROM_INT(102)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S1_IN_D2 ), MP_ROM_INT(103)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S1_IN_D3 ), MP_ROM_INT(104)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S1_OUT_D0 ), MP_ROM_INT(105)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S1_OUT_D1 ), MP_ROM_INT(106)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S1_OUT_D2 ), MP_ROM_INT(107)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S1_OUT_D3 ), MP_ROM_INT(108)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S2_MCLK ), MP_ROM_INT(109)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S2_SCLK ), MP_ROM_INT(110)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S2_WS ), MP_ROM_INT(111)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S2_IN_D0 ), MP_ROM_INT(112)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S2_IN_D1 ), MP_ROM_INT(113)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S2_IN_D2 ), MP_ROM_INT(114)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S2_IN_D3 ), MP_ROM_INT(115)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S2_OUT_D0 ), MP_ROM_INT(116)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S2_OUT_D1 ), MP_ROM_INT(117)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S2_OUT_D2 ), MP_ROM_INT(118)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2S2_OUT_D3 ), MP_ROM_INT(119)},
|
||||
{MP_ROM_QSTR(MP_QSTR_RESV0 ), MP_ROM_INT(120)},
|
||||
{MP_ROM_QSTR(MP_QSTR_RESV1 ), MP_ROM_INT(121)},
|
||||
{MP_ROM_QSTR(MP_QSTR_RESV2 ), MP_ROM_INT(122)},
|
||||
{MP_ROM_QSTR(MP_QSTR_RESV3 ), MP_ROM_INT(123)},
|
||||
{MP_ROM_QSTR(MP_QSTR_RESV4 ), MP_ROM_INT(124)},
|
||||
{MP_ROM_QSTR(MP_QSTR_RESV5 ), MP_ROM_INT(125)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2C0_SCLK ), MP_ROM_INT(126)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2C0_SDA ), MP_ROM_INT(127)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2C1_SCLK ), MP_ROM_INT(128)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2C1_SDA ), MP_ROM_INT(129)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2C2_SCLK ), MP_ROM_INT(130)},
|
||||
{MP_ROM_QSTR(MP_QSTR_I2C2_SDA ), MP_ROM_INT(131)},
|
||||
{MP_ROM_QSTR(MP_QSTR_CMOS_XCLK ), MP_ROM_INT(132)},
|
||||
{MP_ROM_QSTR(MP_QSTR_CMOS_RST ), MP_ROM_INT(133)},
|
||||
{MP_ROM_QSTR(MP_QSTR_CMOS_PWDN ), MP_ROM_INT(134)},
|
||||
{MP_ROM_QSTR(MP_QSTR_CMOS_VSYNC ), MP_ROM_INT(135)},
|
||||
{MP_ROM_QSTR(MP_QSTR_CMOS_HREF ), MP_ROM_INT(136)},
|
||||
{MP_ROM_QSTR(MP_QSTR_CMOS_PCLK ), MP_ROM_INT(137)},
|
||||
{MP_ROM_QSTR(MP_QSTR_CMOS_D0 ), MP_ROM_INT(138)},
|
||||
{MP_ROM_QSTR(MP_QSTR_CMOS_D1 ), MP_ROM_INT(139)},
|
||||
{MP_ROM_QSTR(MP_QSTR_CMOS_D2 ), MP_ROM_INT(140)},
|
||||
{MP_ROM_QSTR(MP_QSTR_CMOS_D3 ), MP_ROM_INT(141)},
|
||||
{MP_ROM_QSTR(MP_QSTR_CMOS_D4 ), MP_ROM_INT(142)},
|
||||
{MP_ROM_QSTR(MP_QSTR_CMOS_D5 ), MP_ROM_INT(143)},
|
||||
{MP_ROM_QSTR(MP_QSTR_CMOS_D6 ), MP_ROM_INT(144)},
|
||||
{MP_ROM_QSTR(MP_QSTR_CMOS_D7 ), MP_ROM_INT(145)},
|
||||
{MP_ROM_QSTR(MP_QSTR_SCCB_SCLK ), MP_ROM_INT(146)},
|
||||
{MP_ROM_QSTR(MP_QSTR_SCCB_SDA ), MP_ROM_INT(147)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART1_CTS ), MP_ROM_INT(148)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART1_DSR ), MP_ROM_INT(149)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART1_DCD ), MP_ROM_INT(150)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART1_RI ), MP_ROM_INT(151)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART1_SIR_IN ), MP_ROM_INT(152)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART1_DTR ), MP_ROM_INT(153)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART1_RTS ), MP_ROM_INT(154)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART1_OUT2 ), MP_ROM_INT(155)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART1_OUT1 ), MP_ROM_INT(156)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART1_SIR_OUT ), MP_ROM_INT(157)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART1_BAUD ), MP_ROM_INT(158)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART1_RE ), MP_ROM_INT(159)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART1_DE ), MP_ROM_INT(160)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART1_RS485_EN), MP_ROM_INT(161)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART2_CTS ), MP_ROM_INT(162)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART2_DSR ), MP_ROM_INT(163)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART2_DCD ), MP_ROM_INT(164)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART2_RI ), MP_ROM_INT(165)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART2_SIR_IN ), MP_ROM_INT(166)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART2_DTR ), MP_ROM_INT(167)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART2_RTS ), MP_ROM_INT(168)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART2_OUT2 ), MP_ROM_INT(169)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART2_OUT1 ), MP_ROM_INT(170)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART2_SIR_OUT ), MP_ROM_INT(171)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART2_BAUD ), MP_ROM_INT(172)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART2_RE ), MP_ROM_INT(173)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART2_DE ), MP_ROM_INT(174)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART2_RS485_EN), MP_ROM_INT(175)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART3_CTS ), MP_ROM_INT(176)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART3_DSR ), MP_ROM_INT(177)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART3_DCD ), MP_ROM_INT(178)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART3_RI ), MP_ROM_INT(179)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART3_SIR_IN ), MP_ROM_INT(180)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART3_DTR ), MP_ROM_INT(181)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART3_RTS ), MP_ROM_INT(182)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART3_OUT2 ), MP_ROM_INT(183)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART3_OUT1 ), MP_ROM_INT(184)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART3_SIR_OUT ), MP_ROM_INT(185)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART3_BAUD ), MP_ROM_INT(186)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART3_RE ), MP_ROM_INT(187)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART3_DE ), MP_ROM_INT(188)},
|
||||
{MP_ROM_QSTR(MP_QSTR_UART3_RS485_EN), MP_ROM_INT(189)},
|
||||
{MP_ROM_QSTR(MP_QSTR_TIMER0_TOGGLE1), MP_ROM_INT(190)},
|
||||
{MP_ROM_QSTR(MP_QSTR_TIMER0_TOGGLE2), MP_ROM_INT(191)},
|
||||
{MP_ROM_QSTR(MP_QSTR_TIMER0_TOGGLE3), MP_ROM_INT(192)},
|
||||
{MP_ROM_QSTR(MP_QSTR_TIMER0_TOGGLE4), MP_ROM_INT(193)},
|
||||
{MP_ROM_QSTR(MP_QSTR_TIMER1_TOGGLE1), MP_ROM_INT(194)},
|
||||
{MP_ROM_QSTR(MP_QSTR_TIMER1_TOGGLE2), MP_ROM_INT(195)},
|
||||
{MP_ROM_QSTR(MP_QSTR_TIMER1_TOGGLE3), MP_ROM_INT(196)},
|
||||
{MP_ROM_QSTR(MP_QSTR_TIMER1_TOGGLE4), MP_ROM_INT(197)},
|
||||
{MP_ROM_QSTR(MP_QSTR_TIMER2_TOGGLE1), MP_ROM_INT(198)},
|
||||
{MP_ROM_QSTR(MP_QSTR_TIMER2_TOGGLE2), MP_ROM_INT(199)},
|
||||
{MP_ROM_QSTR(MP_QSTR_TIMER2_TOGGLE3), MP_ROM_INT(200)},
|
||||
{MP_ROM_QSTR(MP_QSTR_TIMER2_TOGGLE4), MP_ROM_INT(201)},
|
||||
{MP_ROM_QSTR(MP_QSTR_CLK_SPI2 ), MP_ROM_INT(202)},
|
||||
{MP_ROM_QSTR(MP_QSTR_CLK_I2C2 ), MP_ROM_INT(203)},
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(Maix_fpioa_locals_dict, Maix_fpioa_locals_dict_table);
|
||||
const mp_obj_type_t Maix_fpioa_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_FPIOA,
|
||||
.make_new = Maix_fpioa_make_new,
|
||||
.locals_dict = (mp_obj_dict_t*)&Maix_fpioa_locals_dict,
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,587 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* Development of the code in this file was sponsored by Microbric Pty Ltd
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gpio.h"
|
||||
#include "gpiohs.h"
|
||||
#include "plic.h"
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "mphalport.h"
|
||||
#include "modmachine.h"
|
||||
#include "extmod/virtpin.h"
|
||||
|
||||
const mp_obj_type_t Maix_gpio_type;
|
||||
|
||||
typedef int gpio_num_t;
|
||||
enum {
|
||||
GPIO_DM_PULL_NONE = -1,
|
||||
};
|
||||
|
||||
typedef enum _gpio_type_t{
|
||||
GPIOHS = 0,
|
||||
GPIO = 1,
|
||||
}gpio_type_t;
|
||||
|
||||
typedef struct _Maix_gpio_obj_t {
|
||||
mp_obj_base_t base;
|
||||
gpio_num_t num;
|
||||
gpio_type_t gpio_type;
|
||||
gpio_num_t id;
|
||||
mp_obj_t callback;
|
||||
gpio_drive_mode_t mode;
|
||||
|
||||
} Maix_gpio_obj_t;
|
||||
|
||||
typedef struct _Maix_gpio_irq_obj_t {
|
||||
mp_obj_base_t base;
|
||||
gpio_num_t num;
|
||||
gpio_num_t id;
|
||||
} Maix_gpio_irq_obj_t;
|
||||
|
||||
typedef enum __gpio_t{
|
||||
GPIO_NUM_0 = 0,
|
||||
GPIO_NUM_1,
|
||||
GPIO_NUM_2,
|
||||
GPIO_NUM_3,
|
||||
GPIO_NUM_4,
|
||||
GPIO_NUM_5,
|
||||
GPIO_NUM_6,
|
||||
GPIO_NUM_7,
|
||||
}_gpio_t;
|
||||
|
||||
typedef enum __gpiohs_t{
|
||||
GPIOHS_NUM_0 = 0,
|
||||
GPIOHS_NUM_1,
|
||||
GPIOHS_NUM_2,
|
||||
GPIOHS_NUM_3,
|
||||
GPIOHS_NUM_4,
|
||||
GPIOHS_NUM_5,
|
||||
GPIOHS_NUM_6,
|
||||
GPIOHS_NUM_7,
|
||||
GPIOHS_NUM_8,
|
||||
GPIOHS_NUM_9,
|
||||
GPIOHS_NUM_10,
|
||||
GPIOHS_NUM_11,
|
||||
GPIOHS_NUM_12,
|
||||
GPIOHS_NUM_13,
|
||||
GPIOHS_NUM_14,
|
||||
GPIOHS_NUM_15,
|
||||
GPIOHS_NUM_16,
|
||||
GPIOHS_NUM_17,
|
||||
GPIOHS_NUM_18,
|
||||
GPIOHS_NUM_19,
|
||||
GPIOHS_NUM_20,
|
||||
GPIOHS_NUM_21,
|
||||
GPIOHS_NUM_22,
|
||||
GPIOHS_NUM_23,
|
||||
GPIOHS_NUM_24,
|
||||
GPIOHS_NUM_25,
|
||||
GPIOHS_NUM_26,
|
||||
GPIOHS_NUM_27,
|
||||
GPIOHS_NUM_28,
|
||||
GPIOHS_NUM_29,
|
||||
GPIOHS_NUM_30,
|
||||
GPIOHS_NUM_31,
|
||||
} _gpiohs_t;
|
||||
|
||||
STATIC const Maix_gpio_obj_t Maix_gpio_obj[] = {
|
||||
{{&Maix_gpio_type}, 0, GPIOHS, GPIOHS_NUM_0, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 1, GPIOHS, GPIOHS_NUM_1, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 2, GPIOHS, GPIOHS_NUM_2, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 3, GPIOHS, GPIOHS_NUM_3, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 4, GPIOHS, GPIOHS_NUM_4, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 5, GPIOHS, GPIOHS_NUM_5, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 6, GPIOHS, GPIOHS_NUM_6, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 7, GPIOHS, GPIOHS_NUM_7, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 8, GPIOHS, GPIOHS_NUM_8, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 9, GPIOHS, GPIOHS_NUM_9, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 10, GPIOHS, GPIOHS_NUM_10, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 11, GPIOHS, GPIOHS_NUM_11, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 12, GPIOHS, GPIOHS_NUM_12, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 13, GPIOHS, GPIOHS_NUM_13, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 14, GPIOHS, GPIOHS_NUM_14, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 15, GPIOHS, GPIOHS_NUM_15, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 16, GPIOHS, GPIOHS_NUM_16, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 17, GPIOHS, GPIOHS_NUM_17, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 18, GPIOHS, GPIOHS_NUM_18, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 19, GPIOHS, GPIOHS_NUM_19, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 20, GPIOHS, GPIOHS_NUM_20, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 21, GPIOHS, GPIOHS_NUM_21, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 22, GPIOHS, GPIOHS_NUM_22, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 23, GPIOHS, GPIOHS_NUM_23, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 24, GPIOHS, GPIOHS_NUM_24, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 25, GPIOHS, GPIOHS_NUM_25, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 26, GPIOHS, GPIOHS_NUM_26, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 27, GPIOHS, GPIOHS_NUM_27, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 28, GPIOHS, GPIOHS_NUM_28, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 29, GPIOHS, GPIOHS_NUM_29, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 30, GPIOHS, GPIOHS_NUM_30, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 31, GPIOHS, GPIOHS_NUM_31, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 32, GPIO, GPIO_NUM_0, MP_OBJ_NULL, GPIO_DM_INPUT},//32
|
||||
{{&Maix_gpio_type}, 33, GPIO, GPIO_NUM_1, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 34, GPIO, GPIO_NUM_2, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 35, GPIO, GPIO_NUM_3, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 36, GPIO, GPIO_NUM_4, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 37, GPIO, GPIO_NUM_5, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 38, GPIO, GPIO_NUM_6, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
{{&Maix_gpio_type}, 39, GPIO, GPIO_NUM_7, MP_OBJ_NULL, GPIO_DM_INPUT},
|
||||
|
||||
};
|
||||
|
||||
// forward declaration
|
||||
STATIC const Maix_gpio_irq_obj_t Maix_gpio_irq_object[];
|
||||
|
||||
void Maix_gpios_init(void) {
|
||||
// memset(&MP_STATE_PORT(Maix_gpio_irq_handler[0]), 0, sizeof(MP_STATE_PORT(Maix_gpio_irq_handler)));
|
||||
}
|
||||
|
||||
void Maix_gpios_deinit(void) {
|
||||
|
||||
for (int i = 0; i < MP_ARRAY_SIZE(Maix_gpio_obj); ++i) {
|
||||
if (Maix_gpio_obj[i].gpio_type != GPIO) {
|
||||
plic_irq_disable(IRQN_GPIOHS0_INTERRUPT + Maix_gpio_obj[i].id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int Maix_gpio_isr_handler(void *arg) {
|
||||
Maix_gpio_obj_t *self = arg;
|
||||
//only gpiohs support irq,so only support gpiohs in this func
|
||||
mp_obj_t handler = self->callback;
|
||||
// mp_call_function_2(handler, MP_OBJ_FROM_PTR(self), mp_obj_new_int_from_uint(self->id));
|
||||
mp_sched_schedule(handler, MP_OBJ_FROM_PTR(self));
|
||||
mp_hal_wake_main_task_from_isr();
|
||||
return 0;
|
||||
}
|
||||
|
||||
gpio_num_t Maix_gpio_get_id(mp_obj_t pin_in) {
|
||||
if (mp_obj_get_type(pin_in) != &Maix_gpio_type) {
|
||||
mp_raise_ValueError("expecting a pin");
|
||||
}
|
||||
Maix_gpio_obj_t *self = pin_in;
|
||||
return self->id;
|
||||
}
|
||||
|
||||
STATIC void Maix_gpio_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
Maix_gpio_obj_t *self = self_in;
|
||||
|
||||
mp_printf(print, "Pin(%u)", self->id);
|
||||
}
|
||||
|
||||
// pin.init(mode, pull=None, *, value)
|
||||
STATIC mp_obj_t Maix_gpio_obj_init_helper(Maix_gpio_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_mode, ARG_pull, ARG_value };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = mp_const_none}},
|
||||
{ MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}},
|
||||
{ MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
|
||||
};
|
||||
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
// configure mode
|
||||
if (args[ARG_mode].u_obj != mp_const_none) {
|
||||
mp_int_t pin_io_mode = mp_obj_get_int(args[ARG_mode].u_obj);
|
||||
if (0 <= self->num && self->num < MP_ARRAY_SIZE(Maix_gpio_obj)) {
|
||||
self = (Maix_gpio_obj_t*)&Maix_gpio_obj[self->num];
|
||||
if(pin_io_mode == GPIO_DM_OUTPUT && args[ARG_pull].u_obj != mp_const_none && mp_obj_get_int(args[ARG_pull].u_obj) != GPIO_DM_PULL_NONE){
|
||||
mp_raise_ValueError("When this pin is in output mode, it is not allowed to pull up and down.");
|
||||
}else{
|
||||
if(args[ARG_pull].u_obj != mp_const_none && mp_obj_get_int(args[ARG_pull].u_obj) != GPIO_DM_PULL_NONE ){
|
||||
if(mp_obj_get_int(args[ARG_pull].u_obj) == GPIO_DM_INPUT_PULL_UP || mp_obj_get_int(args[ARG_pull].u_obj) == GPIO_DM_INPUT_PULL_DOWN){
|
||||
pin_io_mode = mp_obj_get_int(args[ARG_pull].u_obj);
|
||||
}else{
|
||||
mp_raise_ValueError("this mode not support.");
|
||||
}
|
||||
}
|
||||
if(self->gpio_type == GPIO){
|
||||
gpio_set_drive_mode(self->id, pin_io_mode);
|
||||
}else{
|
||||
gpiohs_set_drive_mode(self->id, pin_io_mode);
|
||||
}
|
||||
self->mode = pin_io_mode;
|
||||
}
|
||||
|
||||
//set initial value (dont this before configuring mode/pull)
|
||||
if (args[ARG_value].u_obj != MP_OBJ_NULL) {
|
||||
if(self->gpio_type == GPIOHS){
|
||||
gpiohs_set_pin((uint8_t)self->id,mp_obj_is_true(args[ARG_value].u_obj));
|
||||
}else{
|
||||
gpio_set_pin((uint8_t)self->id,mp_obj_is_true(args[ARG_value].u_obj));
|
||||
}
|
||||
}
|
||||
}else{
|
||||
mp_raise_ValueError("pin not found");
|
||||
}
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
// constructor(id, ...)
|
||||
mp_obj_t mp_maixpy_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
|
||||
|
||||
// get the wanted pin object
|
||||
int wanted_pin = mp_obj_get_int(args[0]);
|
||||
Maix_gpio_obj_t *self = NULL;
|
||||
if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(Maix_gpio_obj)) {
|
||||
self = (Maix_gpio_obj_t*)&Maix_gpio_obj[wanted_pin];
|
||||
}
|
||||
if (self == NULL || self->base.type == NULL) {
|
||||
mp_raise_ValueError("invalid pin");
|
||||
}
|
||||
|
||||
if (n_args > 1 || n_kw > 0) {
|
||||
// pin mode given, so configure this GPIO
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
Maix_gpio_obj_init_helper(self, n_args - 1, args + 1, &kw_args);
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
// fast method for getting/setting pin value
|
||||
STATIC mp_obj_t Maix_gpio_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||
Maix_gpio_obj_t *self = self_in;
|
||||
if (n_args == 0) {
|
||||
// get pin
|
||||
if(self->gpio_type == GPIO){
|
||||
return MP_OBJ_NEW_SMALL_INT(gpio_get_pin((uint8_t)self->id));
|
||||
}else{
|
||||
if (self->mode == GPIO_DM_OUTPUT) {
|
||||
gpiohs_set_drive_mode((uint8_t)self->id, GPIO_DM_INPUT);
|
||||
}
|
||||
int value = gpiohs_get_pin((uint8_t)self->id);
|
||||
if (self->mode == GPIO_DM_OUTPUT) {
|
||||
gpiohs_set_drive_mode((uint8_t)self->id, GPIO_DM_OUTPUT);
|
||||
}
|
||||
return MP_OBJ_NEW_SMALL_INT(value);
|
||||
}
|
||||
|
||||
} else {
|
||||
// set pin
|
||||
if(self->gpio_type == GPIO){
|
||||
gpio_set_pin(self->id, mp_obj_is_true(args[0]));
|
||||
}else{
|
||||
gpiohs_set_pin(self->id, mp_obj_is_true(args[0]));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
|
||||
// pin.init(mode, pull)
|
||||
STATIC mp_obj_t Maix_gpio_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
return Maix_gpio_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(Maix_gpio_init_obj, 1, Maix_gpio_obj_init);
|
||||
|
||||
// pin.value([value])
|
||||
STATIC mp_obj_t Maix_gpio_value(size_t n_args, const mp_obj_t *args) {
|
||||
return Maix_gpio_call(args[0], n_args - 1, 0, args + 1);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(Maix_gpio_value_obj, 1, 2, Maix_gpio_value);
|
||||
|
||||
// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING)
|
||||
STATIC mp_obj_t Maix_gpio_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_handler, ARG_trigger, ARG_wake ,ARG_priority};
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_PE_BOTH} },
|
||||
{ MP_QSTR_wake, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_priority, MP_ARG_INT, {.u_int = 7} },
|
||||
};
|
||||
Maix_gpio_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
if (self->gpio_type != GPIO && (n_args > 1 || kw_args->used != 0)) {
|
||||
// configure irq
|
||||
mp_obj_t handler = args[ARG_handler].u_obj;
|
||||
uint32_t trigger = args[ARG_trigger].u_int;
|
||||
mp_obj_t wake_obj = args[ARG_wake].u_obj;
|
||||
mp_int_t temp_wake_int;
|
||||
mp_obj_get_int_maybe(args[ARG_wake].u_obj,&temp_wake_int);
|
||||
|
||||
if(wake_obj != mp_const_none && temp_wake_int != 0){
|
||||
mp_raise_ValueError("This platform does not support interrupt wakeup");
|
||||
}else{
|
||||
if (trigger == GPIO_PE_NONE || trigger == GPIO_PE_RISING || trigger == GPIO_PE_FALLING || trigger == GPIO_PE_BOTH) {
|
||||
|
||||
if (handler == mp_const_none) {
|
||||
handler = MP_OBJ_NULL;
|
||||
trigger = 0;
|
||||
}
|
||||
self->callback = handler;
|
||||
gpiohs_set_pin_edge((uint8_t)self->id,trigger);
|
||||
gpiohs_irq_register((uint8_t)self->id, args[ARG_priority].u_int, Maix_gpio_isr_handler, (void *)self);
|
||||
}else{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//return the irq object
|
||||
return MP_OBJ_FROM_PTR(&Maix_gpio_irq_object[self->num]);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(Maix_gpio_irq_obj, 1, Maix_gpio_irq);
|
||||
|
||||
STATIC mp_obj_t Maix_gpio_disirq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
Maix_gpio_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||
|
||||
if (self->gpio_type != GPIO) {
|
||||
plic_irq_disable(IRQN_GPIOHS0_INTERRUPT + (uint8_t)self->id);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(Maix_gpio_disirq_obj,1,Maix_gpio_disirq);
|
||||
|
||||
|
||||
STATIC mp_obj_t Maix_gpio_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
if(!mp_obj_is_type(pos_args[0], &Maix_gpio_type))
|
||||
mp_raise_ValueError("only for object");
|
||||
Maix_gpio_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||
|
||||
enum { ARG_mode};
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_mode, MP_ARG_INT, {.u_int = -1} },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
if(args[ARG_mode].u_int == -1)
|
||||
{
|
||||
return mp_obj_new_int(self->mode);
|
||||
}
|
||||
else if(args[ARG_mode].u_int != GPIO_DM_INPUT &&
|
||||
args[ARG_mode].u_int != GPIO_DM_OUTPUT &&
|
||||
args[ARG_mode].u_int != GPIO_DM_PULL_NONE &&
|
||||
args[ARG_mode].u_int != GPIO_DM_INPUT_PULL_UP &&
|
||||
args[ARG_mode].u_int != GPIO_DM_INPUT_PULL_DOWN
|
||||
)
|
||||
{
|
||||
mp_raise_ValueError("arg error");
|
||||
}
|
||||
if (self->gpio_type == GPIO) {
|
||||
gpio_set_drive_mode(self->id, (gpio_drive_mode_t)args[ARG_mode].u_int);
|
||||
}else{
|
||||
gpiohs_set_drive_mode(self->id, (gpio_drive_mode_t)args[ARG_mode].u_int);
|
||||
}
|
||||
self->mode = (gpio_drive_mode_t)args[ARG_mode].u_int;
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(Maix_gpio_mode_obj,1,Maix_gpio_mode);
|
||||
|
||||
|
||||
STATIC const mp_rom_map_elem_t Maix_gpio_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&Maix_gpio_init_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&Maix_gpio_value_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&Maix_gpio_irq_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_disirq), MP_ROM_PTR(&Maix_gpio_disirq_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&Maix_gpio_mode_obj) },
|
||||
// class constants
|
||||
{ MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_DM_INPUT) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_DM_OUTPUT) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PULL_NONE), MP_ROM_INT(GPIO_DM_PULL_NONE) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_DM_INPUT_PULL_UP) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_DM_INPUT_PULL_DOWN) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_NONE), MP_ROM_INT(GPIO_PE_NONE) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_PE_RISING) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_PE_FALLING) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_BOTH), MP_ROM_INT(GPIO_PE_BOTH) },
|
||||
|
||||
// gpio constant
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS0), MP_ROM_INT(GPIOHS_NUM_0) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS1), MP_ROM_INT(GPIOHS_NUM_1) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS2), MP_ROM_INT(GPIOHS_NUM_2) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS3), MP_ROM_INT(GPIOHS_NUM_3) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS4), MP_ROM_INT(GPIOHS_NUM_4) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS5), MP_ROM_INT(GPIOHS_NUM_5) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS6), MP_ROM_INT(GPIOHS_NUM_6) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS7), MP_ROM_INT(GPIOHS_NUM_7) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS8), MP_ROM_INT(GPIOHS_NUM_8) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS9), MP_ROM_INT(GPIOHS_NUM_9) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS10), MP_ROM_INT(GPIOHS_NUM_10) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS11), MP_ROM_INT(GPIOHS_NUM_11) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS12), MP_ROM_INT(GPIOHS_NUM_12) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS13), MP_ROM_INT(GPIOHS_NUM_13) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS14), MP_ROM_INT(GPIOHS_NUM_14) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS15), MP_ROM_INT(GPIOHS_NUM_15) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS16), MP_ROM_INT(GPIOHS_NUM_16) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS17), MP_ROM_INT(GPIOHS_NUM_17) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS18), MP_ROM_INT(GPIOHS_NUM_18) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS19), MP_ROM_INT(GPIOHS_NUM_19) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS20), MP_ROM_INT(GPIOHS_NUM_20) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS21), MP_ROM_INT(GPIOHS_NUM_21) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS22), MP_ROM_INT(GPIOHS_NUM_22) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS23), MP_ROM_INT(GPIOHS_NUM_23) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS24), MP_ROM_INT(GPIOHS_NUM_24) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS25), MP_ROM_INT(GPIOHS_NUM_25) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS26), MP_ROM_INT(GPIOHS_NUM_26) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS27), MP_ROM_INT(GPIOHS_NUM_27) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS28), MP_ROM_INT(GPIOHS_NUM_28) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS29), MP_ROM_INT(GPIOHS_NUM_29) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS30), MP_ROM_INT(GPIOHS_NUM_30) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIOHS31), MP_ROM_INT(GPIOHS_NUM_31) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIO0), MP_ROM_INT(32) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIO1), MP_ROM_INT(33) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIO2), MP_ROM_INT(34) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIO3), MP_ROM_INT(35) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIO4), MP_ROM_INT(36) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIO5), MP_ROM_INT(37) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIO6), MP_ROM_INT(38) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIO7), MP_ROM_INT(39) },
|
||||
|
||||
//wakeup not support
|
||||
{ MP_ROM_QSTR(MP_QSTR_WAKEUP_NOT_SUPPORT), MP_ROM_INT(0) },
|
||||
};
|
||||
|
||||
STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
|
||||
(void)errcode;
|
||||
Maix_gpio_obj_t *self = self_in;
|
||||
|
||||
switch (request) {
|
||||
case MP_PIN_READ: {
|
||||
if(self->gpio_type == GPIO){
|
||||
return gpio_get_pin((uint8_t)self->id);
|
||||
}else{
|
||||
return gpio_get_pin((uint8_t)self->id);
|
||||
}
|
||||
}
|
||||
case MP_PIN_WRITE: {
|
||||
if(self->gpio_type == GPIO){
|
||||
gpio_set_pin((uint8_t)self->id, arg);
|
||||
}else{
|
||||
gpiohs_set_pin((uint8_t)self->id, arg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(Maix_gpio_locals_dict, Maix_gpio_locals_dict_table);
|
||||
|
||||
STATIC const mp_pin_p_t pin_pin_p = {
|
||||
.ioctl = pin_ioctl,
|
||||
};
|
||||
|
||||
const mp_obj_type_t Maix_gpio_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Pin,
|
||||
.print = Maix_gpio_print,
|
||||
.make_new = mp_maixpy_pin_make_new,
|
||||
.call = Maix_gpio_call,
|
||||
.protocol = &pin_pin_p,
|
||||
.locals_dict = (mp_obj_t)&Maix_gpio_locals_dict,
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
// Pin IRQ object
|
||||
|
||||
STATIC const mp_obj_type_t Maix_gpio_irq_type;
|
||||
|
||||
STATIC const Maix_gpio_irq_obj_t Maix_gpio_irq_object[] = {
|
||||
{{&Maix_gpio_irq_type}, 0, GPIOHS_NUM_0},
|
||||
{{&Maix_gpio_irq_type}, 1, GPIOHS_NUM_1},
|
||||
{{&Maix_gpio_irq_type}, 2, GPIOHS_NUM_2},
|
||||
{{&Maix_gpio_irq_type}, 3, GPIOHS_NUM_3},
|
||||
{{&Maix_gpio_irq_type}, 4, GPIOHS_NUM_4},
|
||||
{{&Maix_gpio_irq_type}, 5, GPIOHS_NUM_5},
|
||||
{{&Maix_gpio_irq_type}, 6, GPIOHS_NUM_6},
|
||||
{{&Maix_gpio_irq_type}, 7, GPIOHS_NUM_7},
|
||||
{{&Maix_gpio_irq_type}, 8, GPIOHS_NUM_8},
|
||||
{{&Maix_gpio_irq_type}, 9, GPIOHS_NUM_9},
|
||||
{{&Maix_gpio_irq_type}, 10, GPIOHS_NUM_10},
|
||||
{{&Maix_gpio_irq_type}, 11, GPIOHS_NUM_11},
|
||||
{{&Maix_gpio_irq_type}, 12, GPIOHS_NUM_12},
|
||||
{{&Maix_gpio_irq_type}, 13, GPIOHS_NUM_13},
|
||||
{{&Maix_gpio_irq_type}, 14, GPIOHS_NUM_14},
|
||||
{{&Maix_gpio_irq_type}, 15, GPIOHS_NUM_15},
|
||||
{{&Maix_gpio_irq_type}, 16, GPIOHS_NUM_16},
|
||||
{{&Maix_gpio_irq_type}, 17, GPIOHS_NUM_17},
|
||||
{{&Maix_gpio_irq_type}, 18, GPIOHS_NUM_18},
|
||||
{{&Maix_gpio_irq_type}, 19, GPIOHS_NUM_19},
|
||||
{{&Maix_gpio_irq_type}, 20, GPIOHS_NUM_20},
|
||||
{{&Maix_gpio_irq_type}, 21, GPIOHS_NUM_21},
|
||||
{{&Maix_gpio_irq_type}, 22, GPIOHS_NUM_22},
|
||||
{{&Maix_gpio_irq_type}, 23, GPIOHS_NUM_23},
|
||||
{{&Maix_gpio_irq_type}, 24, GPIOHS_NUM_24},
|
||||
{{&Maix_gpio_irq_type}, 25, GPIOHS_NUM_25},
|
||||
{{&Maix_gpio_irq_type}, 26, GPIOHS_NUM_26},
|
||||
{{&Maix_gpio_irq_type}, 27, GPIOHS_NUM_27},
|
||||
{{&Maix_gpio_irq_type}, 28, GPIOHS_NUM_28},
|
||||
{{&Maix_gpio_irq_type}, 29, GPIOHS_NUM_29},
|
||||
{{&Maix_gpio_irq_type}, 30, GPIOHS_NUM_30},
|
||||
{{&Maix_gpio_irq_type}, 31, GPIOHS_NUM_31},
|
||||
};
|
||||
|
||||
STATIC mp_obj_t Maix_gpio_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
Maix_gpio_irq_obj_t *self = self_in;
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
Maix_gpio_isr_handler((void*)&Maix_gpio_obj[self->num]);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t Maix_gpio_irq_trigger(size_t n_args, const mp_obj_t *args) {
|
||||
Maix_gpio_irq_obj_t *self = args[0];
|
||||
if (n_args == 2) {
|
||||
// set trigger
|
||||
gpiohs_set_pin_edge(self->id,mp_obj_get_int(args[1]));
|
||||
}else{
|
||||
mp_raise_ValueError("Reading this property is not supported");
|
||||
}
|
||||
// not support to return original trigger value
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(Maix_gpio_irq_trigger_obj, 1, 2, Maix_gpio_irq_trigger);
|
||||
|
||||
STATIC const mp_rom_map_elem_t Maix_gpio_irq_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_trigger), MP_ROM_PTR(&Maix_gpio_irq_trigger_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(Maix_gpio_irq_locals_dict, Maix_gpio_irq_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t Maix_gpio_irq_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_IRQ,
|
||||
.call = Maix_gpio_irq_call,
|
||||
.locals_dict = (mp_obj_dict_t*)&Maix_gpio_irq_locals_dict,
|
||||
};
|
||||
@ -0,0 +1,371 @@
|
||||
/*
|
||||
* Copyright 2019 Sipeed Co.,Ltd.
|
||||
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "i2s.h"
|
||||
#include "dmac.h"
|
||||
#include "sysctl.h"
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
|
||||
#include "modMaix.h"
|
||||
#include "py_audio.h"
|
||||
#include "Maix_i2s.h"
|
||||
#define MAX_SAMPLE_RATE (4*1024*1024)
|
||||
#define MAX_SAMPLE_POINTS (64*1024)
|
||||
|
||||
const mp_obj_type_t Maix_i2s_type;
|
||||
|
||||
|
||||
STATIC void Maix_i2s_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
Maix_i2s_obj_t* self = MP_OBJ_TO_PTR(self_in);
|
||||
// i2s_channle_t* channel_iter = &self->channel[0];
|
||||
mp_printf(print, "[MAIXPY]i2s%d:(sampling rate=%u, sampling points=%u)\n",
|
||||
self->i2s_num,self->sample_rate,self->points_num);
|
||||
for(int channel_iter = 0; channel_iter < 4; channel_iter++)
|
||||
{
|
||||
mp_printf(print, "[MAIXPY]channle%d:(resolution=%u, cycles=%u, align_mode=%u, mode=%u)\n",
|
||||
channel_iter,
|
||||
self->channel[channel_iter].resolution,
|
||||
self->channel[channel_iter].cycles,
|
||||
self->channel[channel_iter].align_mode,
|
||||
self->channel[channel_iter].mode);
|
||||
}
|
||||
}
|
||||
STATIC mp_obj_t Maix_i2s_init_helper(Maix_i2s_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum
|
||||
{
|
||||
ARG_sample_points,
|
||||
ARG_pll2,
|
||||
ARG_mclk,
|
||||
};
|
||||
static const mp_arg_t allowed_args[] =
|
||||
{
|
||||
{ MP_QSTR_sample_points, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1024} },
|
||||
{ MP_QSTR_pll2, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_mclk, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
|
||||
if (args[ARG_pll2].u_int != 0) // 262144000UL
|
||||
{
|
||||
sysctl_pll_set_freq(SYSCTL_PLL2, args[ARG_pll2].u_int);
|
||||
}
|
||||
|
||||
if (args[ARG_mclk].u_int != 0) // 31 an 16384000 / (16000 * 256) = 4 ;
|
||||
{
|
||||
sysctl_clock_set_threshold(SYSCTL_THRESHOLD_I2S0_M + self->i2s_num, args[ARG_mclk].u_int);
|
||||
}
|
||||
|
||||
//set buffer len
|
||||
if(args[ARG_sample_points].u_int > MAX_SAMPLE_POINTS)
|
||||
{
|
||||
mp_raise_ValueError("[MAIXPY]I2S:invalid buffer length");
|
||||
}
|
||||
self->points_num = args[ARG_sample_points].u_int;
|
||||
self->buf = m_new(uint32_t,self->points_num);
|
||||
|
||||
//set i2s channel mask
|
||||
self->chn_mask = 0;
|
||||
|
||||
return mp_const_true;
|
||||
}
|
||||
STATIC mp_obj_t Maix_i2s_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
|
||||
|
||||
// get i2s num
|
||||
mp_int_t i2s_num = mp_obj_get_int(args[0]);
|
||||
if (i2s_num >= I2S_DEVICE_MAX) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "[MAIXPY]I2S%d:does not exist", i2s_num));
|
||||
}
|
||||
|
||||
// create instance
|
||||
Maix_i2s_obj_t *self = m_new_obj(Maix_i2s_obj_t);
|
||||
self->base.type = &Maix_i2s_type;
|
||||
self->i2s_num = i2s_num;
|
||||
self->sample_rate = 0;
|
||||
memset(&self->channel,0,4 * sizeof(i2s_channle_t));
|
||||
|
||||
// init instance
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
Maix_i2s_init_helper(self, n_args - 1, args + 1, &kw_args);
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t Maix_i2s_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
return Maix_i2s_init_helper(args[0], n_args -1 , args + 1, kw_args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(Maix_i2s_init_obj, 0, Maix_i2s_init);
|
||||
|
||||
STATIC mp_obj_t Maix_i2s_channel_config(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
|
||||
{
|
||||
//get i2s obj
|
||||
Maix_i2s_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||
|
||||
//parse parameter
|
||||
enum{ARG_channel,
|
||||
ARG_mode,
|
||||
ARG_resolution,
|
||||
ARG_cycles,
|
||||
ARG_align_mode,
|
||||
};
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_channel, MP_ARG_INT, {.u_int = I2S_CHANNEL_0} },
|
||||
{ MP_QSTR_mode, MP_ARG_INT, {.u_int = I2S_RECEIVER} },
|
||||
{ MP_QSTR_resolution, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = RESOLUTION_16_BIT} },
|
||||
{ MP_QSTR_cycles, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SCLK_CYCLES_32} },
|
||||
{ MP_QSTR_align_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = STANDARD_MODE} },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args-1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
//set channel
|
||||
if(args[ARG_channel].u_int > I2S_CHANNEL_3)
|
||||
{
|
||||
mp_raise_ValueError("[MAIXPY]I2S:invalid i2s channle");
|
||||
}
|
||||
i2s_channel_num_t channel_num = args[ARG_channel].u_int;
|
||||
i2s_channle_t* channle = &self->channel[channel_num];
|
||||
|
||||
//set resolution
|
||||
if(args[ARG_resolution].u_int > RESOLUTION_32_BIT )
|
||||
{
|
||||
mp_raise_ValueError("[MAIXPY]I2S:invalid resolution");
|
||||
}
|
||||
channle->resolution = args[ARG_resolution].u_int;
|
||||
if(args[ARG_cycles].u_int > SCLK_CYCLES_32 )
|
||||
{
|
||||
mp_raise_ValueError("[MAIXPY]I2S:invalid cycles");
|
||||
}
|
||||
channle->cycles = args[ARG_cycles].u_int;
|
||||
self->cycles = args[ARG_cycles].u_int;
|
||||
|
||||
//set align mode
|
||||
if(args[ARG_align_mode].u_int != STANDARD_MODE && args[ARG_align_mode].u_int != RIGHT_JUSTIFYING_MODE && args[ARG_align_mode].u_int != LEFT_JUSTIFYING_MODE)
|
||||
{
|
||||
mp_raise_ValueError("[MAIXPY]I2S:invalid align mode");
|
||||
}
|
||||
channle->align_mode = args[ARG_align_mode].u_int;
|
||||
|
||||
//set mode
|
||||
if(args[ARG_mode].u_int > I2S_RECEIVER )
|
||||
{
|
||||
mp_raise_ValueError("[MAIXPY]I2S:invalid cycles");
|
||||
}
|
||||
channle->mode = args[ARG_mode].u_int;
|
||||
|
||||
//running config
|
||||
if(channle->mode == I2S_RECEIVER)
|
||||
{
|
||||
self->chn_mask |= 0x3 << (channel_num * 2);
|
||||
i2s_init(self->i2s_num, I2S_RECEIVER, self->chn_mask);
|
||||
i2s_rx_channel_config(self->i2s_num,
|
||||
channel_num,
|
||||
channle->resolution,
|
||||
channle->cycles,
|
||||
TRIGGER_LEVEL_4,
|
||||
channle->align_mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->chn_mask |= 0x3 << (channel_num * 2);
|
||||
i2s_init(self->i2s_num, I2S_TRANSMITTER,self->chn_mask);
|
||||
i2s_tx_channel_config(self->i2s_num,
|
||||
channel_num,
|
||||
channle->resolution,
|
||||
channle->cycles,
|
||||
TRIGGER_LEVEL_4,
|
||||
channle->align_mode);
|
||||
}
|
||||
return mp_const_true;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(Maix_i2s_channel_config_obj, 2, Maix_i2s_channel_config);
|
||||
|
||||
STATIC mp_obj_t Maix_i2s_set_sample_rate(void* self_, mp_obj_t sample_rate)
|
||||
{
|
||||
Maix_i2s_obj_t* self = (Maix_i2s_obj_t*)self_;
|
||||
uint32_t smp_rate = mp_obj_get_int(sample_rate);
|
||||
if(smp_rate > MAX_SAMPLE_RATE)
|
||||
{
|
||||
mp_raise_ValueError("[MAIXPY]I2S:invalid sample rate");
|
||||
}
|
||||
int res = i2s_set_sample_rate(self->i2s_num,smp_rate);
|
||||
|
||||
//judege cycles,which channel should we select ?
|
||||
if(self->cycles == SCLK_CYCLES_16)
|
||||
{
|
||||
self->sample_rate = res / 32;
|
||||
}
|
||||
else if(self->cycles == SCLK_CYCLES_24)
|
||||
{
|
||||
self->sample_rate = res / 48;
|
||||
}
|
||||
else if(self->cycles == SCLK_CYCLES_32)
|
||||
{
|
||||
self->sample_rate = res / 64;
|
||||
}
|
||||
return mp_const_true;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(Maix_i2s_set_sample_rate_obj,Maix_i2s_set_sample_rate);
|
||||
|
||||
|
||||
STATIC mp_obj_t Maix_i2s_record(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)//point_nums,time
|
||||
{
|
||||
//get i2s obj
|
||||
Maix_i2s_obj_t *self = pos_args[0];
|
||||
Maix_audio_obj_t *audio_obj = m_new_obj(Maix_audio_obj_t);
|
||||
audio_obj->audio.type = I2S_AUDIO;
|
||||
//parse parameter
|
||||
enum{ARG_points,
|
||||
ARG_time,
|
||||
};
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_points, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_time, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args-1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
audio_obj->base.type = &Maix_audio_type;
|
||||
|
||||
//compute buffer length
|
||||
if(args[ARG_points].u_int > 0)
|
||||
{
|
||||
if(audio_obj->audio.points > self->points_num)
|
||||
{
|
||||
mp_raise_ValueError("[MAIXPY]I2S:Too many points");
|
||||
}
|
||||
audio_obj->audio.points = args[ARG_points].u_int;
|
||||
char* audio_buf = m_new(uint32_t, audio_obj->audio.points);
|
||||
if (audio_buf == NULL) {
|
||||
mp_raise_ValueError("[MAIXPY]I2S:create audio new buf error");
|
||||
}
|
||||
memcpy(audio_buf, self->buf, sizeof(uint32_t) * audio_obj->audio.points);
|
||||
audio_obj->audio.buf = audio_buf;
|
||||
}
|
||||
else if(args[ARG_time].u_int > 0)
|
||||
{
|
||||
if(self->sample_rate <= 0)
|
||||
mp_raise_ValueError("[MAIXPY]I2S:please set sample rate");
|
||||
uint32_t record_sec = args[ARG_time].u_int;
|
||||
uint32_t smp_points = self->sample_rate * record_sec;
|
||||
if(smp_points > self->points_num)
|
||||
mp_raise_ValueError("[MAIXPY]I2S:sampling size is out of bounds");
|
||||
audio_obj->audio.points = smp_points;
|
||||
char* audio_buf = m_new(uint32_t, audio_obj->audio.points);
|
||||
if (audio_buf == NULL)
|
||||
{
|
||||
mp_raise_ValueError("[MAIXPY]I2S:create audio new buf error");
|
||||
}
|
||||
memcpy(audio_buf, self->buf, sizeof(uint32_t) * smp_points);
|
||||
audio_obj->audio.buf = audio_buf;
|
||||
}else
|
||||
{
|
||||
mp_raise_ValueError("[MAIXPY]I2S:please input recording points or time");
|
||||
}
|
||||
|
||||
//record
|
||||
i2s_receive_data_dma(self->i2s_num, audio_obj->audio.buf, audio_obj->audio.points , DMAC_CHANNEL3);
|
||||
// dmac_wait_idle(DMAC_CHANNEL3);//wait to finish recv
|
||||
return MP_OBJ_FROM_PTR(audio_obj);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(Maix_i2s_record_obj,1,Maix_i2s_record);
|
||||
|
||||
STATIC mp_obj_t Maix_i2s_wait_record(void*self_)
|
||||
{
|
||||
dmac_wait_idle(DMAC_CHANNEL3);//wait to finish recv
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(Maix_i2s_wait_record_obj, Maix_i2s_wait_record);
|
||||
|
||||
STATIC mp_obj_t Maix_i2s_play(void*self_, mp_obj_t audio_obj)
|
||||
{
|
||||
Maix_i2s_obj_t* self = (Maix_i2s_obj_t*)self_;
|
||||
Maix_audio_obj_t *audio_p = MP_OBJ_TO_PTR(audio_obj);
|
||||
i2s_send_data_dma(self->i2s_num, audio_p->audio.buf, audio_p->audio.points, DMAC_CHANNEL4);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(Maix_i2s_play_obj,Maix_i2s_play);
|
||||
|
||||
STATIC mp_obj_t Maix_i2s_deinit(void*self_)
|
||||
{
|
||||
Maix_i2s_obj_t* self = (Maix_i2s_obj_t*)self_;
|
||||
m_del(uint32_t,self->buf,self->points_num);
|
||||
m_del_obj(Maix_i2s_obj_t,self);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(Maix_i2s_deinit_obj,Maix_i2s_deinit);
|
||||
|
||||
// STATIC MP_DEFINE_CONST_FUN_OBJ_KW(Maix_i2s_set_dma_divede_16_obj,1,);
|
||||
// STATIC MP_DEFINE_CONST_FUN_OBJ_KW(Maix_i2s_set_dma_divede_16_obj,1,);
|
||||
|
||||
|
||||
STATIC const mp_rom_map_elem_t Maix_i2s_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___deinit__), MP_ROM_PTR(&Maix_i2s_deinit_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&Maix_i2s_init_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_channel_config), MP_ROM_PTR(&Maix_i2s_channel_config_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_sample_rate), MP_ROM_PTR(&Maix_i2s_set_sample_rate_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_record), MP_ROM_PTR(&Maix_i2s_record_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_wait_record), MP_ROM_PTR(&Maix_i2s_wait_record_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&Maix_i2s_play_obj) },
|
||||
//advance interface , some user don't use it
|
||||
// { MP_ROM_QSTR(MP_QSTR_set_dma_divede_16), MP_ROM_PTR(&Maix_i2s_set_dma_divede_16_obj) },
|
||||
// { MP_ROM_QSTR(MP_QSTR_set_dma_divede_16), MP_ROM_PTR(&Maix_i2s_get_dma_divede_16_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DEVICE_0), MP_ROM_INT(I2S_DEVICE_0) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DEVICE_1), MP_ROM_INT(I2S_DEVICE_1) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DEVICE_2), MP_ROM_INT(I2S_DEVICE_2) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_CHANNEL_0), MP_ROM_INT(I2S_CHANNEL_0) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_CHANNEL_1), MP_ROM_INT(I2S_CHANNEL_1) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_CHANNEL_2), MP_ROM_INT(I2S_CHANNEL_2) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_CHANNEL_3), MP_ROM_INT(I2S_CHANNEL_3) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IGNORE_WORD_LENGTH), MP_ROM_INT(IGNORE_WORD_LENGTH) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_RESOLUTION_12_BIT), MP_ROM_INT(RESOLUTION_12_BIT) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_RESOLUTION_16_BIT), MP_ROM_INT(RESOLUTION_16_BIT) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_RESOLUTION_20_BIT), MP_ROM_INT(RESOLUTION_20_BIT) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_RESOLUTION_24_BIT), MP_ROM_INT(RESOLUTION_24_BIT) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_RESOLUTION_32_BIT), MP_ROM_INT(RESOLUTION_32_BIT) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_SCLK_CYCLES_16), MP_ROM_INT(SCLK_CYCLES_16) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SCLK_CYCLES_24), MP_ROM_INT(SCLK_CYCLES_24) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SCLK_CYCLES_32), MP_ROM_INT(SCLK_CYCLES_32) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_TRANSMITTER), MP_ROM_INT(I2S_TRANSMITTER) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_RECEIVER), MP_ROM_INT(I2S_RECEIVER) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_STANDARD_MODE), MP_ROM_INT(STANDARD_MODE) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_RIGHT_JUSTIFYING_MODE), MP_ROM_INT(RIGHT_JUSTIFYING_MODE) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_LEFT_JUSTIFYING_MODE), MP_ROM_INT(LEFT_JUSTIFYING_MODE) },
|
||||
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(Maix_i2s_dict, Maix_i2s_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t Maix_i2s_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_I2S,
|
||||
.print = Maix_i2s_print,
|
||||
.make_new = Maix_i2s_make_new,
|
||||
.locals_dict = (mp_obj_dict_t*)&Maix_i2s_dict,
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,290 @@
|
||||
#include "mpconfig.h"
|
||||
#include "global_config.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py_image.h"
|
||||
#include "sipeed_kpu_classifier.h"
|
||||
#include "Maix_kpu.h"
|
||||
#include "sipeed_kpu.h"
|
||||
#include "py_helper.h"
|
||||
|
||||
const mp_obj_type_t Maix_kpu_classifier_type;
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
void* obj;
|
||||
py_kpu_net_obj_t* kpu_model;
|
||||
kpu_model_info_t* model;
|
||||
} maix_kpu_classifier_t;
|
||||
|
||||
|
||||
STATIC void init_obj(maix_kpu_classifier_t* self, py_kpu_net_obj_t* model, mp_int_t class_num, mp_int_t sample_num, int feature_length){
|
||||
self->model = m_new(kpu_model_info_t, 1);
|
||||
self->kpu_model = model;
|
||||
self->model->kmodel_ctx = model->kmodel_ctx;
|
||||
self->model->max_layers = model->max_layers;
|
||||
self->model->model_addr = model->model_addr;
|
||||
if(model->model_path == mp_const_none)
|
||||
self->model->model_path = NULL;
|
||||
else
|
||||
self->model->model_path = mp_obj_str_get_str(model->model_path);
|
||||
self->model->model_size = model->model_size;
|
||||
int ret = maix_kpu_classifier_init(&self->obj, self->model, (int)class_num, (int)sample_num, false, 0, feature_length);
|
||||
if(ret < 0)
|
||||
mp_raise_OSError(-ret);
|
||||
}
|
||||
|
||||
STATIC int add_class_img(maix_kpu_classifier_t* self, image_t* img, int idx){
|
||||
int ret = maix_kpu_classifier_add_class_img(self->obj, img, idx);
|
||||
if(ret < 0)
|
||||
mp_raise_OSError(-ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC int rm_class_img(maix_kpu_classifier_t* self){
|
||||
int ret = maix_kpu_classifier_rm_class_img(self->obj);
|
||||
if(ret < 0)
|
||||
mp_raise_OSError(-ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC int add_sample_img(maix_kpu_classifier_t* self, image_t* img){
|
||||
int ret = maix_kpu_classifier_add_sample_img(self->obj, img);
|
||||
if(ret < 0)
|
||||
mp_raise_OSError(-ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC int rm_sample_img(maix_kpu_classifier_t* self){
|
||||
int ret = maix_kpu_classifier_rm_sample_img(self->obj);
|
||||
if(ret < 0)
|
||||
mp_raise_OSError(-ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC void clear_obj(maix_kpu_classifier_t* self){
|
||||
int ret = maix_kpu_classifier_del(&self->obj);
|
||||
if(ret < 0)
|
||||
mp_raise_OSError(-ret);
|
||||
}
|
||||
|
||||
STATIC void train(maix_kpu_classifier_t* self){
|
||||
int ret = maix_kpu_classifier_train(self->obj);
|
||||
if(ret < 0)
|
||||
mp_raise_OSError(-ret);
|
||||
}
|
||||
|
||||
STATIC int predict(maix_kpu_classifier_t* self, image_t* img, float* min_distance){
|
||||
int ret = maix_kpu_classifier_predict(self->obj, img, min_distance, NULL, NULL, NULL, NULL);
|
||||
if(ret < 0)
|
||||
mp_raise_OSError(-ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
STATIC void save_trained_model(maix_kpu_classifier_t* self, const char* path){
|
||||
int ret = maix_kpu_classifier_save(self->obj, path);
|
||||
if(ret < 0)
|
||||
mp_raise_OSError(-ret);
|
||||
}
|
||||
|
||||
STATIC void load_trained_model(maix_kpu_classifier_t* self, const char* path, py_kpu_net_obj_t* model, int* class_num, int* sample_num, int feature_length){
|
||||
self->model = m_new(kpu_model_info_t, 1);
|
||||
self->kpu_model = model;
|
||||
self->model->kmodel_ctx = model->kmodel_ctx;
|
||||
self->model->max_layers = model->max_layers;
|
||||
self->model->model_addr = model->model_addr;
|
||||
if(model->model_path == mp_const_none)
|
||||
self->model->model_path = NULL;
|
||||
else
|
||||
self->model->model_path = mp_obj_str_get_str(model->model_path);
|
||||
self->model->model_size = model->model_size;
|
||||
int ret = maix_kpu_classifier_load(&self->obj, path, self->model, class_num, sample_num, feature_length);
|
||||
if(ret < 0)
|
||||
mp_raise_OSError(-ret);
|
||||
}
|
||||
|
||||
mp_obj_t maix_kpu_classifier_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
maix_kpu_classifier_t* self = m_new_obj_with_finaliser(maix_kpu_classifier_t);
|
||||
self->base.type = &Maix_kpu_classifier_type;
|
||||
self->obj = NULL;
|
||||
if(n_args<3)
|
||||
{
|
||||
mp_raise_ValueError("model, class num, sample num");
|
||||
}
|
||||
if(mp_obj_get_type(args[0]) != &py_kpu_net_obj_type){
|
||||
mp_raise_ValueError("model");
|
||||
}
|
||||
int feature_length = 0;
|
||||
if(n_kw > 0)
|
||||
{
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
feature_length = py_helper_keyword_int(n_args, args, 3, &kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fea_len), 0);
|
||||
}
|
||||
sipeed_kpu_use_dma(1);
|
||||
init_obj(self, (py_kpu_net_obj_t*)args[0], mp_obj_get_int(args[1]), mp_obj_get_int(args[2]), feature_length);
|
||||
return (mp_obj_t)self;
|
||||
}
|
||||
|
||||
mp_obj_t classifier_add_class_img(size_t n_args, const mp_obj_t *args){
|
||||
if(mp_obj_get_type(args[0]) != &Maix_kpu_classifier_type){
|
||||
mp_raise_ValueError("must be obj");
|
||||
}
|
||||
maix_kpu_classifier_t* self = (maix_kpu_classifier_t*)args[0];
|
||||
image_t* img = py_image_cobj(args[1]);
|
||||
int idx = -1;
|
||||
if(n_args > 2)
|
||||
idx = mp_obj_get_int(args[2]);
|
||||
int ret_index = add_class_img(self, img, idx);
|
||||
return mp_obj_new_int(ret_index);
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(classifier_add_class_img_obj, 2, 3, classifier_add_class_img);
|
||||
|
||||
|
||||
mp_obj_t classifier_rm_class_img(mp_obj_t self_in){
|
||||
if(mp_obj_get_type(self_in) != &Maix_kpu_classifier_type){
|
||||
mp_raise_ValueError("must be obj");
|
||||
}
|
||||
maix_kpu_classifier_t* self = (maix_kpu_classifier_t*)self_in;
|
||||
int ret_index = rm_class_img(self);
|
||||
return mp_obj_new_int(ret_index);
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(classifier_rm_class_img_obj, classifier_rm_class_img);
|
||||
|
||||
|
||||
mp_obj_t classifier_add_sample_img(mp_obj_t self_in, mp_obj_t img_in){
|
||||
if(mp_obj_get_type(self_in) != &Maix_kpu_classifier_type){
|
||||
mp_raise_ValueError("must be obj");
|
||||
}
|
||||
maix_kpu_classifier_t* self = (maix_kpu_classifier_t*)self_in;
|
||||
image_t* img = py_image_cobj(img_in);
|
||||
int ret = add_sample_img(self, img);
|
||||
return mp_obj_new_int(ret);
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(classifier_add_sample_img_obj, classifier_add_sample_img);
|
||||
|
||||
mp_obj_t classifier_rm_sample_img(mp_obj_t self_in){
|
||||
if(mp_obj_get_type(self_in) != &Maix_kpu_classifier_type){
|
||||
mp_raise_ValueError("must be obj");
|
||||
}
|
||||
maix_kpu_classifier_t* self = (maix_kpu_classifier_t*)self_in;
|
||||
int ret_index = rm_sample_img(self);
|
||||
return mp_obj_new_int(ret_index);
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(classifier_rm_sample_img_obj, classifier_rm_sample_img);
|
||||
|
||||
mp_obj_t classifier_del(mp_obj_t self_in){
|
||||
if(mp_obj_get_type(self_in) != &Maix_kpu_classifier_type){
|
||||
mp_raise_ValueError("must be obj");
|
||||
}
|
||||
mp_printf(&mp_plat_print, "classifier __del__\r\n");
|
||||
maix_kpu_classifier_t* self = (maix_kpu_classifier_t*)self_in;
|
||||
clear_obj(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(classifier_del_obj, classifier_del);
|
||||
|
||||
mp_obj_t classifier_train(mp_obj_t self_in){
|
||||
if(mp_obj_get_type(self_in) != &Maix_kpu_classifier_type){
|
||||
mp_raise_ValueError("must be obj");
|
||||
}
|
||||
maix_kpu_classifier_t* self = (maix_kpu_classifier_t*)self_in;
|
||||
train(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(classifier_train_obj, classifier_train);
|
||||
|
||||
mp_obj_t classifier_predict(mp_obj_t self_in, mp_obj_t img_in){
|
||||
if(mp_obj_get_type(self_in) != &Maix_kpu_classifier_type){
|
||||
mp_raise_ValueError("must be obj");
|
||||
}
|
||||
maix_kpu_classifier_t* self = (maix_kpu_classifier_t*)self_in;
|
||||
image_t* img = py_image_cobj(img_in);
|
||||
float min_distance;
|
||||
int ret_index = predict(self, img, &min_distance);
|
||||
mp_obj_t t[2];
|
||||
t[0] = mp_obj_new_int(ret_index);
|
||||
t[1] = mp_obj_new_float(min_distance);
|
||||
return mp_obj_new_tuple(2,t);
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(classifier_predict_obj, classifier_predict);
|
||||
|
||||
|
||||
mp_obj_t classifier_save(mp_obj_t self_in, mp_obj_t path_in){
|
||||
if(mp_obj_get_type(self_in) != &Maix_kpu_classifier_type){
|
||||
mp_raise_ValueError("must be obj");
|
||||
}
|
||||
maix_kpu_classifier_t* self = (maix_kpu_classifier_t*)self_in;
|
||||
const char* path = mp_obj_str_get_str(path_in);
|
||||
save_trained_model(self, path);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(classifier_save_obj, classifier_save);
|
||||
|
||||
/**
|
||||
* @param model_in kpu model object
|
||||
* @param path_in saved classifier model path
|
||||
* @param class_num init object classnum, if not set, the same as saved model's
|
||||
* @param sample_num ...
|
||||
*/
|
||||
mp_obj_t classifier_load(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args){
|
||||
mp_obj_t model_in = args[0];
|
||||
mp_obj_t path_in = args[1];
|
||||
if(mp_obj_get_type(model_in) == &Maix_kpu_classifier_type){
|
||||
mp_raise_ValueError("must be class");
|
||||
}
|
||||
if(mp_obj_get_type(model_in) != &py_kpu_net_obj_type){
|
||||
mp_raise_ValueError("must be model");
|
||||
}
|
||||
if(mp_obj_get_type(path_in) != &mp_type_str){
|
||||
mp_raise_ValueError("path err");
|
||||
}
|
||||
maix_kpu_classifier_t* self = m_new_obj_with_finaliser(maix_kpu_classifier_t);
|
||||
self->base.type = &Maix_kpu_classifier_type;
|
||||
self->obj = NULL;
|
||||
int class_num = 0, sample_num = 0;
|
||||
if(n_args > 2)
|
||||
{
|
||||
class_num = mp_obj_get_int(args[2]);
|
||||
}
|
||||
if(n_args > 3)
|
||||
{
|
||||
sample_num = mp_obj_get_int(args[3]);
|
||||
}
|
||||
int feature_length = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fea_len), 0);
|
||||
load_trained_model(self, mp_obj_str_get_str(path_in), (py_kpu_net_obj_t*)model_in, &class_num, &sample_num, feature_length);
|
||||
mp_obj_t* items[3] = {(mp_obj_t)self, mp_obj_new_int(class_num), mp_obj_new_int(sample_num)};
|
||||
return mp_obj_new_tuple(3, items);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(classifier_load_obj, 2, classifier_load);
|
||||
|
||||
|
||||
STATIC const mp_map_elem_t locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_classifier) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_add_class_img), (mp_obj_t)(&classifier_add_class_img_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_add_sample_img), (mp_obj_t)(&classifier_add_sample_img_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_train), (mp_obj_t)(&classifier_train_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_predict), (mp_obj_t)(&classifier_predict_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___del__), (mp_obj_t)(&classifier_del_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_rm_class_img), (mp_obj_t)(&classifier_rm_class_img_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_rm_sample_img), (mp_obj_t)(&classifier_rm_sample_img_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_save), (mp_obj_t)(&classifier_save_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_load), (mp_obj_t)(&classifier_load_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(locals_dict, locals_dict_table);
|
||||
|
||||
const mp_obj_type_t Maix_kpu_classifier_type = {
|
||||
.base = { &mp_type_type },
|
||||
.name = MP_QSTR_classifier,
|
||||
.make_new = maix_kpu_classifier_make_new,
|
||||
.locals_dict = (mp_obj_dict_t*)&locals_dict
|
||||
};
|
||||
|
||||
@ -0,0 +1,286 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/objarray.h"
|
||||
#include "py/binary.h"
|
||||
#include "py_assert.h"
|
||||
#include "mperrno.h"
|
||||
#include "mphalport.h"
|
||||
#include "modMaix.h"
|
||||
#include "imlib.h"
|
||||
|
||||
#include "sleep.h"
|
||||
#include "lcd.h"
|
||||
#include "sysctl.h"
|
||||
#include "fpioa.h"
|
||||
#include "lib_mic.h"
|
||||
#include "sipeed_sk9822.h"
|
||||
#include "py_image.h"
|
||||
|
||||
#define PLL2_OUTPUT_FREQ 45158400UL
|
||||
|
||||
STATIC uint16_t colormap_parula[64] = {
|
||||
0x3935, 0x4156, 0x4178, 0x4199, 0x41ba, 0x41db, 0x421c, 0x423d,
|
||||
0x4a7e, 0x429e, 0x42df, 0x42ff, 0x431f, 0x435f, 0x3b7f, 0x3bbf,
|
||||
0x33ff, 0x2c1f, 0x2c3e, 0x2c7e, 0x2c9d, 0x24bd, 0x24dd, 0x251c,
|
||||
0x1d3c, 0x1d5c, 0x1d7b, 0x159a, 0x05ba, 0x05d9, 0x05d8, 0x0df7,
|
||||
0x1e16, 0x2615, 0x2e34, 0x3634, 0x3652, 0x3e51, 0x4e70, 0x566f,
|
||||
0x666d, 0x766c, 0x866b, 0x8e49, 0x9e48, 0xae27, 0xbe26, 0xc605,
|
||||
0xd5e4, 0xdde5, 0xe5c5, 0xf5c6, 0xfdc7, 0xfde7, 0xfe27, 0xfe46,
|
||||
0xfe86, 0xfea5, 0xf6e5, 0xf704, 0xf744, 0xf764, 0xffa3, 0xffc2};
|
||||
|
||||
STATIC uint16_t colormap_parula_rect[64][14 * 14] __attribute__((aligned(128)));
|
||||
|
||||
STATIC int init_colormap_parula_rect()
|
||||
{
|
||||
for (uint32_t i = 0; i < 64; i++)
|
||||
{
|
||||
for (uint32_t j = 0; j < 14 * 14; j++)
|
||||
{
|
||||
colormap_parula_rect[i][j] = colormap_parula[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
STATIC uint8_t lib_init_flag = 0;
|
||||
|
||||
STATIC volatile uint8_t mic_done = 0;
|
||||
STATIC uint8_t thermal_map_data[256];
|
||||
|
||||
STATIC void lib_mic_cb(void)
|
||||
{
|
||||
mic_done = 1;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t Maix_mic_array_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
|
||||
{
|
||||
enum {
|
||||
ARG_i2s_d0,
|
||||
ARG_i2s_d1,
|
||||
ARG_i2s_d2,
|
||||
ARG_i2s_d3,
|
||||
ARG_i2s_ws,
|
||||
ARG_i2s_sclk,
|
||||
|
||||
ARG_sk9822_dat,
|
||||
ARG_sk9822_clk,
|
||||
};
|
||||
|
||||
// sysctl_pll_set_freq(SYSCTL_PLL2, PLL2_OUTPUT_FREQ); //如果使用i2s,必须设置PLL2
|
||||
static const mp_arg_t allowed_args[]={
|
||||
{MP_QSTR_i2s_d0, MP_ARG_INT, {.u_int = 23}},
|
||||
{MP_QSTR_i2s_d1, MP_ARG_INT, {.u_int = 22}},
|
||||
{MP_QSTR_i2s_d2, MP_ARG_INT, {.u_int = 21}},
|
||||
{MP_QSTR_i2s_d3, MP_ARG_INT, {.u_int = 20}},
|
||||
{MP_QSTR_i2s_ws, MP_ARG_INT, {.u_int = 19}},
|
||||
{MP_QSTR_i2s_sclk, MP_ARG_INT, {.u_int = 18}},
|
||||
|
||||
{MP_QSTR_sk9822_dat, MP_ARG_INT, {.u_int = 24}},
|
||||
{MP_QSTR_sk9822_clk, MP_ARG_INT, {.u_int = 25}},
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
//evil code
|
||||
fpioa_set_function(args[ARG_i2s_d0].u_int, FUNC_I2S0_IN_D0);
|
||||
fpioa_set_function(args[ARG_i2s_d1].u_int, FUNC_I2S0_IN_D1);
|
||||
fpioa_set_function(args[ARG_i2s_d2].u_int, FUNC_I2S0_IN_D2);
|
||||
fpioa_set_function(args[ARG_i2s_d3].u_int, FUNC_I2S0_IN_D3);
|
||||
fpioa_set_function(args[ARG_i2s_ws].u_int, FUNC_I2S0_WS);
|
||||
fpioa_set_function(args[ARG_i2s_sclk].u_int, FUNC_I2S0_SCLK);
|
||||
//TODO: optimize Soft SPI
|
||||
fpioa_set_function(args[ARG_sk9822_dat].u_int, FUNC_GPIOHS0 + SK9822_DAT_GPIONUM);
|
||||
fpioa_set_function(args[ARG_sk9822_clk].u_int, FUNC_GPIOHS0 + SK9822_CLK_GPIONUM);
|
||||
|
||||
// init_colormap_parula_rect();
|
||||
sipeed_init_mic_array_led();
|
||||
|
||||
int ret = lib_mic_init(DMAC_CHANNEL4, lib_mic_cb, thermal_map_data);
|
||||
if(ret != 0)
|
||||
{
|
||||
char tmp[64];
|
||||
sprintf(tmp,"lib_mic init error with %d",ret);
|
||||
mp_raise_ValueError((const char*)tmp);
|
||||
return mp_const_false;
|
||||
}
|
||||
lib_init_flag = 1;
|
||||
// sysctl_enable_irq();
|
||||
return mp_const_true;
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(Maix_mic_array_init_obj, 0, Maix_mic_array_init);
|
||||
|
||||
STATIC mp_obj_t Maix_mic_array_deinit(void)
|
||||
{
|
||||
if(lib_init_flag)
|
||||
{
|
||||
lib_mic_deinit();
|
||||
lib_init_flag = 0;
|
||||
}
|
||||
return mp_const_true;
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(Maix_mic_array_deinit_obj, Maix_mic_array_deinit);
|
||||
|
||||
STATIC mp_obj_t Maix_mic_array_get_map(void)
|
||||
{
|
||||
image_t out;
|
||||
|
||||
out.w = 16;
|
||||
out.h = 16;
|
||||
out.bpp = IMAGE_BPP_GRAYSCALE;
|
||||
out.data = xalloc(256);
|
||||
mic_done = 0;
|
||||
|
||||
volatile uint8_t retry = 100;
|
||||
|
||||
while(mic_done == 0)
|
||||
{
|
||||
retry--;
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
if(mic_done == 0 && retry == 0)
|
||||
{
|
||||
xfree(out.data);
|
||||
mp_raise_OSError(MP_ETIMEDOUT);
|
||||
return mp_const_false;
|
||||
}
|
||||
|
||||
memcpy(out.data, thermal_map_data, 256);
|
||||
|
||||
return py_image_from_struct(&out);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(Maix_mic_array_get_map_obj, Maix_mic_array_get_map);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
STATIC uint8_t voice_strength_len[12] = {14, 20, 14, 14, 20, 14, 14, 20, 14, 14, 20, 14};
|
||||
|
||||
//voice strength, to calc direction
|
||||
STATIC uint8_t voice_strength[12][32] = {
|
||||
{197, 198, 199, 213, 214, 215, 228, 229, 230, 231, 244, 245, 246, 247}, //14
|
||||
{178, 179, 192, 193, 194, 195, 196, 208, 209, 210, 211, 212, 224, 225, 226, 227, 240, 241, 242, 243}, //20
|
||||
{128, 129, 130, 131, 144, 145, 146, 147, 160, 161, 162, 163, 176, 177},
|
||||
{64, 65, 80, 81, 82, 83, 96, 97, 98, 99, 112, 113, 114, 115},
|
||||
{0, 1, 2, 3, 16, 17, 18, 19, 32, 33, 34, 35, 36, 48, 49, 50, 51, 52, 66, 67},
|
||||
{4, 5, 6, 7, 20, 21, 22, 23, 37, 38, 39, 53, 54, 55},
|
||||
{8, 9, 10, 11, 24, 25, 26, 27, 40, 41, 42, 56, 57, 58},
|
||||
{12, 13, 14, 15, 28, 29, 30, 31, 43, 44, 45, 46, 47, 59, 60, 61, 62, 63, 76, 77},
|
||||
{78, 79, 92, 93, 94, 95, 108, 109, 110, 111, 124, 125, 126, 127},
|
||||
{140, 141, 142, 143, 156, 157, 158, 159, 173, 172, 174, 175, 190, 191},
|
||||
{188, 189, 203, 204, 205, 206, 207, 219, 220, 221, 222, 223, 236, 237, 238, 239, 252, 253, 254, 255},
|
||||
{200, 201, 202, 216, 217, 218, 232, 233, 234, 235, 248, 249, 250, 251},
|
||||
};
|
||||
|
||||
STATIC void calc_voice_strength(uint8_t *voice_data, uint8_t *led_brightness)
|
||||
{
|
||||
uint32_t tmp_sum[12] = {0};
|
||||
uint8_t i, index, tmp;
|
||||
|
||||
for (index = 0; index < 12; index++)
|
||||
{
|
||||
tmp_sum[index] = 0;
|
||||
for (i = 0; i < voice_strength_len[index]; i++)
|
||||
{
|
||||
tmp_sum[index] += voice_data[voice_strength[index][i]];
|
||||
}
|
||||
tmp = (uint8_t)tmp_sum[index] / voice_strength_len[index];
|
||||
led_brightness[index] = tmp > 15 ? 15 : tmp;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t Maix_mic_array_get_dir(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
|
||||
{
|
||||
uint8_t led_brightness[12]={0};
|
||||
|
||||
image_t *arg_img = py_image_cobj(pos_args[0]);
|
||||
PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported.");
|
||||
|
||||
if(arg_img->w!=16 || arg_img->h!=16 || arg_img->bpp!=IMAGE_BPP_GRAYSCALE)
|
||||
{
|
||||
mp_raise_ValueError("image type error, only support 16*16 grayscale image");
|
||||
return mp_const_false;
|
||||
}
|
||||
|
||||
calc_voice_strength(arg_img->data, led_brightness);
|
||||
|
||||
mp_obj_t *tuple, *tmp;
|
||||
|
||||
tmp = (mp_obj_t *)malloc(12 * sizeof(mp_obj_t));
|
||||
|
||||
for (uint8_t index = 0; index < 12; index++)
|
||||
tmp[index] = mp_obj_new_int(led_brightness[index]);
|
||||
|
||||
tuple = mp_obj_new_tuple(12, tmp);
|
||||
|
||||
free(tmp);
|
||||
|
||||
return tuple;
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(Maix_mic_array_get_dir_obj, 1, Maix_mic_array_get_dir);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
STATIC mp_obj_t Maix_mic_array_set_led(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
|
||||
{
|
||||
int index, brightness[12] = {0}, led_color[12] = {0}, color[3] = {0};
|
||||
|
||||
mp_obj_t *items;
|
||||
mp_obj_get_array_fixed_n(pos_args[0], 12, &items);
|
||||
|
||||
for(index= 0; index < 12; index++)
|
||||
brightness[index] = mp_obj_get_int(items[index]);
|
||||
|
||||
mp_obj_get_array_fixed_n(pos_args[1], 3, &items);
|
||||
for(index = 0; index < 3; index++)
|
||||
color[index] = mp_obj_get_int(items[index]);
|
||||
|
||||
//rgb
|
||||
uint32_t set_color = (color[2] << 16) | (color[1] << 8) | (color[0]);
|
||||
|
||||
for (index = 0; index < 12; index++)
|
||||
{
|
||||
led_color[index] = (brightness[index] / 2) > 1 ? (((0xe0 | (brightness[index] * 2)) << 24) | set_color) : 0xe0000000;
|
||||
}
|
||||
|
||||
//FIXME close irq?
|
||||
sysctl_disable_irq();
|
||||
sk9822_start_frame();
|
||||
for (index = 0; index < 12; index++)
|
||||
{
|
||||
sk9822_send_data(led_color[index]);
|
||||
}
|
||||
sk9822_stop_frame();
|
||||
|
||||
sysctl_enable_irq();
|
||||
|
||||
return mp_const_true;
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(Maix_mic_array_set_led_obj, 2, Maix_mic_array_set_led);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
STATIC const mp_rom_map_elem_t Maix_mic_array_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&Maix_mic_array_init_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&Maix_mic_array_deinit_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_get_dir), MP_ROM_PTR(&Maix_mic_array_get_dir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_led), MP_ROM_PTR(&Maix_mic_array_set_led_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_get_map), MP_ROM_PTR(&Maix_mic_array_get_map_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(Maix_mic_array_dict, Maix_mic_array_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t Maix_mic_array_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_MIC_ARRAY,
|
||||
.locals_dict = (mp_obj_dict_t*)&Maix_mic_array_dict,
|
||||
};
|
||||
@ -0,0 +1,86 @@
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "mpconfigboard.h"
|
||||
#include "stdint.h"
|
||||
#include "stdbool.h"
|
||||
#include "stdlib.h"
|
||||
#include "sipeed_mem.h"
|
||||
#include "w25qxx.h"
|
||||
|
||||
STATIC mp_obj_t py_gc_heap_size(size_t n_args, const mp_obj_t *args) {
|
||||
config_data_t config;
|
||||
load_config_from_spiffs(&config);
|
||||
if(n_args == 0)
|
||||
return mp_obj_new_int(config.gc_heap_size);
|
||||
else if(n_args != 1)
|
||||
mp_raise_OSError(MP_EINVAL);
|
||||
config.gc_heap_size = mp_obj_get_int(args[0]);
|
||||
if( !save_config_to_spiffs(&config) )
|
||||
mp_raise_OSError(MP_EIO);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_gc_heap_size_obj, 0, 1, py_gc_heap_size);
|
||||
|
||||
// sys_free(): return the number of bytes of available sys heap RAM
|
||||
STATIC mp_obj_t py_heap_free(void) {
|
||||
return MP_OBJ_NEW_SMALL_INT(get_free_heap_size2());
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(py_heap_free_obj, py_heap_free);
|
||||
|
||||
// STATIC mp_obj_t py_malloc(mp_obj_t arg) {
|
||||
// void malloc_stats(void);
|
||||
// malloc_stats();
|
||||
// void* p = malloc(mp_obj_get_int(arg));
|
||||
// return mp_obj_new_int((mp_int_t)p);
|
||||
// }
|
||||
|
||||
// STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_malloc_obj, py_malloc);
|
||||
|
||||
// STATIC mp_obj_t py_free(mp_obj_t arg) {
|
||||
// free(mp_obj_get_int(arg));
|
||||
// return mp_const_none;
|
||||
// }
|
||||
|
||||
// STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_free_obj, py_free);
|
||||
|
||||
|
||||
// STATIC mp_obj_t py_flash_write(mp_obj_t addr, mp_obj_t data_in) {
|
||||
// mp_buffer_info_t bufinfo;
|
||||
// mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
|
||||
// w25qxx_status_t status = w25qxx_write_data_dma(mp_obj_get_int(addr), bufinfo.buf, (uint32_t)bufinfo.len);
|
||||
// return mp_obj_new_int(status); // (status != W25QXX_OK)
|
||||
// }
|
||||
|
||||
// STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_flash_write_obj, py_flash_write);
|
||||
|
||||
STATIC mp_obj_t py_flash_read(mp_obj_t addr, mp_obj_t len_in) {
|
||||
size_t length = mp_obj_get_int(len_in);
|
||||
byte* data = m_new(byte, length);
|
||||
w25qxx_status_t status = w25qxx_read_data_dma(mp_obj_get_int(addr), data, (uint32_t)length, W25QXX_QUAD_FAST);
|
||||
if(status != W25QXX_OK)
|
||||
{
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
return mp_obj_new_bytes(data, length);
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_flash_read_obj, py_flash_read);
|
||||
|
||||
static const mp_map_elem_t locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_utils) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_gc_heap_size), (mp_obj_t)(&py_gc_heap_size_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_heap_free), (mp_obj_t)(&py_heap_free_obj) },
|
||||
// { MP_ROM_QSTR(MP_QSTR_malloc), (mp_obj_t)(&py_malloc_obj) },
|
||||
// { MP_ROM_QSTR(MP_QSTR_free), (mp_obj_t)(&py_free_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_flash_read), (mp_obj_t)(&py_flash_read_obj) },
|
||||
// { MP_ROM_QSTR(MP_QSTR_flash_write), (mp_obj_t)(&py_flash_write_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(locals_dict, locals_dict_table);
|
||||
|
||||
const mp_obj_type_t Maix_utils_type = {
|
||||
.base = { &mp_type_type },
|
||||
.name = MP_QSTR_utils,
|
||||
.locals_dict = (mp_obj_dict_t*)&locals_dict
|
||||
};
|
||||
@ -0,0 +1,5 @@
|
||||
#include "obj.h"
|
||||
|
||||
mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, size_t *cur);
|
||||
mp_obj_t maix_config_init();
|
||||
mp_obj_t maix_config_get_value(mp_obj_t key, mp_obj_t def_value);
|
||||
@ -0,0 +1,23 @@
|
||||
#ifndef MICROPY_MAIX_I2S_H
|
||||
#define MICROPY_MAIX_I2S_H
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "i2s.h"
|
||||
typedef struct _i2s_channle_t{
|
||||
i2s_word_length_t resolution;
|
||||
i2s_word_select_cycles_t cycles;
|
||||
i2s_work_mode_t align_mode;
|
||||
i2s_transmit_t mode;
|
||||
}i2s_channle_t;
|
||||
|
||||
typedef struct _Maix_i2s_obj_t {
|
||||
mp_obj_base_t base;
|
||||
i2s_device_number_t i2s_num;
|
||||
i2s_channle_t channel[4];
|
||||
uint32_t sample_rate;
|
||||
uint32_t points_num;
|
||||
uint32_t* buf;
|
||||
i2s_word_select_cycles_t cycles;
|
||||
uint32_t chn_mask;
|
||||
} Maix_i2s_obj_t;
|
||||
#endif
|
||||
@ -0,0 +1,25 @@
|
||||
#ifndef __MAIX_KPU_H
|
||||
#define __MAIX_KPU_H
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
typedef struct py_kpu_net_obj
|
||||
{
|
||||
mp_obj_base_t base;
|
||||
|
||||
void* kmodel_ctx; //sipeed_model_ctx_t
|
||||
mp_obj_t model_size;
|
||||
mp_obj_t model_addr;
|
||||
mp_obj_t model_path;
|
||||
mp_obj_t max_layers;
|
||||
mp_obj_t net_args; // for yolo2
|
||||
mp_obj_t net_deinit; // for yolo2
|
||||
} __attribute__((aligned(8))) py_kpu_net_obj_t;
|
||||
|
||||
extern const mp_obj_type_t py_kpu_net_obj_type;
|
||||
|
||||
extern const mp_obj_type_t Maix_kpu_classifier_type;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2019 Sipeed Co.,Ltd.
|
||||
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef MICROPY_INCLUDED_MAIX_MAIX_H
|
||||
#define MICROPY_INCLUDED_MAIX_MAIX_H
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "i2s.h"
|
||||
|
||||
extern const mp_obj_type_t Maix_fpioa_type;
|
||||
extern const mp_obj_type_t Maix_gpio_type;
|
||||
extern const mp_obj_type_t Maix_i2s_type;
|
||||
extern const mp_obj_type_t Maix_audio_type;
|
||||
extern const mp_obj_type_t Maix_fft_type;
|
||||
extern const mp_obj_type_t Maix_mic_array_type;
|
||||
extern const mp_obj_type_t cpufreq_type;
|
||||
extern const mp_obj_type_t Maix_utils_type;
|
||||
extern const mp_obj_type_t Maix_config_type;
|
||||
#endif // MICROPY_INCLUDED_MAIX_MAIX_H
|
||||
@ -0,0 +1,11 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* CPU Frequency module.
|
||||
*
|
||||
*/
|
||||
#ifndef __PY_CPUFREQ_H__
|
||||
#define __PY_CPUFREQ_H__
|
||||
#endif // __PY_CPUFREQ_H__
|
||||
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2019 Sipeed Co.,Ltd.
|
||||
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "modMaix.h"
|
||||
|
||||
STATIC const mp_rom_map_elem_t maix_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_machine) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_FPIOA), MP_ROM_PTR(&Maix_fpioa_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIO), MP_ROM_PTR(&Maix_gpio_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_I2S), MP_ROM_PTR(&Maix_i2s_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Audio), MP_ROM_PTR(&Maix_audio_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_FFT), MP_ROM_PTR(&Maix_fft_type) },
|
||||
#if CONFIG_MAIXPY_MIC_ARRAY_ENABLE
|
||||
{ MP_ROM_QSTR(MP_QSTR_MIC_ARRAY), MP_ROM_PTR(&Maix_mic_array_type) },
|
||||
#endif
|
||||
{ MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&cpufreq_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_utils), MP_ROM_PTR(&Maix_utils_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&Maix_config_type) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT (
|
||||
maix_module_globals,
|
||||
maix_module_globals_table
|
||||
);
|
||||
|
||||
const mp_obj_module_t maix_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&maix_module_globals,
|
||||
};
|
||||
|
||||
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* CPU frequency scaling module.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <mp.h>
|
||||
#include <math.h>
|
||||
#include "sysctl.h"
|
||||
#include "py_cpufreq.h"
|
||||
#include "py_helper.h"
|
||||
#include "mpconfigboard.h"
|
||||
#include "vfs_spiffs.h"
|
||||
#include "sipeed_sys.h"
|
||||
|
||||
|
||||
#define ARRAY_LENGTH(x) (sizeof(x)/sizeof(x[0]))
|
||||
// static const uint32_t kpufreq_freqs[] = {100, 200, 400};
|
||||
//static const uint32_t cpufreq_pllq[] = {5, 6, 7, 8, 9};
|
||||
|
||||
// static const uint32_t cpufreq_latency[] = { // Flash latency (see table 11)
|
||||
// FLASH_LATENCY_3, FLASH_LATENCY_4, FLASH_LATENCY_5, FLASH_LATENCY_7, FLASH_LATENCY_7
|
||||
// };
|
||||
|
||||
uint32_t cpufreq_get_cpuclk()
|
||||
{
|
||||
uint32_t cpuclk = sysctl_clock_get_freq(SYSCTL_CLOCK_CPU);
|
||||
|
||||
return cpuclk;
|
||||
}
|
||||
|
||||
mp_obj_t py_cpufreq_get_current_frequencies()
|
||||
{
|
||||
mp_obj_t tuple[2] = {
|
||||
mp_obj_new_int(cpufreq_get_cpuclk() / (1000000)),
|
||||
mp_obj_new_int(sysctl_clock_get_freq(SYSCTL_CLOCK_AI) / (1000000)),
|
||||
};
|
||||
return mp_obj_new_tuple(2, tuple);
|
||||
}
|
||||
|
||||
// mp_obj_t py_kpufreq_get_supported_frequencies()
|
||||
// {
|
||||
|
||||
// mp_obj_t freq_list = mp_obj_new_list(0, NULL);
|
||||
// for (int i=0; i<ARRAY_LENGTH(kpufreq_freqs); i++) {
|
||||
// mp_obj_list_append(freq_list, mp_obj_new_int(kpufreq_freqs[i]));
|
||||
// }
|
||||
// return freq_list;
|
||||
// }
|
||||
|
||||
mp_obj_t py_kpufreq_get_cpu()
|
||||
{
|
||||
return mp_obj_new_int(cpufreq_get_cpuclk() / (1000000));
|
||||
}
|
||||
|
||||
mp_obj_t py_kpufreq_get_kpu()
|
||||
{
|
||||
return mp_obj_new_int(sysctl_clock_get_freq(SYSCTL_CLOCK_AI) / (1000000));
|
||||
}
|
||||
|
||||
mp_obj_t py_cpufreq_set_frequency(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
|
||||
{
|
||||
config_data_t config;
|
||||
enum {
|
||||
ARG_cpu,
|
||||
ARG_pll1,
|
||||
ARG_kpu_div,
|
||||
};
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_cpu, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_pll1, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_kpu_div, MP_ARG_INT, {.u_int = 0} },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
load_config_from_spiffs(&config);
|
||||
|
||||
if(args[ARG_cpu].u_int != 0)
|
||||
config.freq_cpu = args[ARG_cpu].u_int*1000000;
|
||||
if(args[ARG_pll1].u_int != 0)
|
||||
config.freq_pll1 = args[ARG_pll1].u_int*1000000;
|
||||
if(args[ARG_kpu_div].u_int != 0)
|
||||
config.kpu_div = args[ARG_kpu_div].u_int;
|
||||
uint32_t freq_kpu = config.freq_pll1 / config.kpu_div;
|
||||
// Frequency is Not supported.
|
||||
if ( freq_kpu > FREQ_KPU_MAX ||
|
||||
freq_kpu < FREQ_KPU_MIN) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Unsupported KPU frequency!"));
|
||||
}
|
||||
|
||||
// Frequency is Not supported.
|
||||
if ( config.freq_cpu > FREQ_CPU_MAX ||
|
||||
config.freq_cpu < FREQ_CPU_MIN ) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Unsupported CPU frequency!"));
|
||||
}
|
||||
|
||||
// Return if frequency hasn't changed.
|
||||
if (( 20 > abs(config.freq_cpu - cpufreq_get_cpuclk())) && ( 20 > abs(freq_kpu - sysctl_clock_get_freq(SYSCTL_CLOCK_AI) ))) {
|
||||
mp_printf(&mp_plat_print, "No change\r\n");
|
||||
return mp_const_none;
|
||||
}
|
||||
if(!save_config_to_spiffs(&config))
|
||||
mp_printf(&mp_plat_print, "save config fail");
|
||||
mp_printf(&mp_plat_print, "\r\nreboot now\r\n");
|
||||
mp_hal_delay_ms(50);
|
||||
sipeed_sys_reset();
|
||||
|
||||
return mp_const_true;
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_cpufreq_set_freq_obj,0, py_cpufreq_set_frequency);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_cpufreq_get_current_freq_obj, py_cpufreq_get_current_frequencies);
|
||||
// STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_kpufreq_get_supported_frequencies_obj, py_kpufreq_get_supported_frequencies);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_kpufreq_get_kpu_obj, py_kpufreq_get_kpu);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_kpufreq_get_cpu_obj, py_kpufreq_get_cpu);
|
||||
|
||||
static const mp_map_elem_t locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_freq) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_set), (mp_obj_t)&py_cpufreq_set_freq_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_get), (mp_obj_t)&py_cpufreq_get_current_freq_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_get_kpu), (mp_obj_t)&py_kpufreq_get_kpu_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_get_cpu), (mp_obj_t)&py_kpufreq_get_cpu_obj },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(locals_dict, locals_dict_table);
|
||||
|
||||
const mp_obj_type_t cpufreq_type = {
|
||||
.base = { &mp_type_type },
|
||||
.name = MP_QSTR_freq,
|
||||
.locals_dict = (mp_obj_t)&locals_dict,
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue