Giúp File Đọc Số ra Âm thanh dùng trong Khu Cách Ly COVID-19 (6 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

  • hunglam123

    Thành viên bị đình chỉ hoạt động
    Thành viên bị đình chỉ hoạt động
    Tham gia
    31/3/20
    Bài viết
    180
    Được thích
    43
    Em xin chào cả nhà. Hiện tại bên công ty đã đều em đến 1 trung tâm quản lý các bệnh nhân cách ly tại Quận 9 ( Em làm bên nghành y tế ) . hằng ngày cứ 3 lần em đều thấy mấy anh Quân Nhân phải đọc số để Đo nhiệt độ và phát cơm mổi ngày. Nên em nghỉ ra ý tưởng lập 1 file excel để khi nhập số vào nhấn nút đọc thì âm thanh từ máy tính sẽ phát ra Loa bên ngoài. để mọi người như đều nghe thấy
    Giao diện như thế này


    Vùng B4:B15 là vùng lấy đường dẫn File âm thanh. Tức nhiên em đã thu âm các số 0,1,2,3..9 và câu mở đầu và câu kết thúc
    Tại ô F4 em muốn nhập số bệnh nhân vào
    Tại ô G4 em nhập số lần lặp lại
    Nhấn nút Đọc số thì chương trình đọc ra âm thanh.
    Ví dụ gõ số 0123 thì Loa phát ra " Xin mời quý khách mang số . không Một Hai Ba . Vui lòng đến quầy "

    Do kiến thức em hạn hẹp em chỉ tạo mỗi được giao diện , và em đã thu âm và đã đổi sang đươi WAV hết, và các câu lệnh lấy đường dẫn âm thanh. Phần đọc số em chưa biết dùng câu lệnh gì.
    rất mong mọi người cùng cac bang Quản Trị Viên giúp đở để chương trình đưa ra hoạt động giúp đở cộng đồng vướt qua mùa dịch này. Một lần nữa em xin chân thành cảm ơn
     
    Lần chỉnh sửa cuối:
    Hàm này chưa chuẩn anh ơi, anh xem trong file đính kèm nhé.

    Chỗ tải file thì link kia trả về là tập tin audio luôn nên theo em dùng URLDownloadToFile API cho nhanh.

    Vậy quy trình với TTS của Google đại khái: encode chuỗi và ghép vào link TTS, tải file audio, mở file audio.
    --------------------------


    Vì bác batman1 đang "show" nên "show" cho màu mè thôi.

    ----------------------
    PHP:
    Function EncodeURL(strText)
        If Application.Version >= 15 Then
        EncodeURL= Application.EncodeURL(strText)
        Else
        Static objHtmlfile As Object
        If objHtmlfile Is Nothing Then
            Set objHtmlfile = VBA.CreateObject("htmlfile")
            objHtmlfile.parentWindow.execScript "function encode(s) {return encodeURIComponent(s)}", "jscript"
        End If
        EncodeURL = objHtmlfile.parentWindow.encode(strText)
        End If
    End Function
     
    Upvote 0
    Tôi đã viết rõ là đơn giản nhất là dùng PlaySound. Và đổi WMA thành WAV vì PlaySound không phục vụ WMA.

    Còn máy vạn năng thì là mciSendString rồi.

    Về mciSendString tôi cũng đã viết hơn 7,5 năm rồi.

    ------------
    Về bài #8 thì sao lại khởi động chrome? Thứ nhất là khởi động trình duyệt sẽ lâu, thứ 2 là không phải ai cũng dùng chrome. Tôi trước kia dùng IE, bây giờ dùng Firefox. Chưa bao giờ dùng trình duyệt nào khác.

    Trong tập tin đính kèm tôi không khởi động trình duyệt nào cả.

    Tôi cũng tự viết hàm utf8_encode.

    google text to speech rất giỏi, nhưng nhiều khi dịch vẫn không chuẩn, nhiều khi dịch rất buồn cười. Nhưng cho nhu cầu chủ đề này hoàn toàn được.

    Những ai chưa biết cách lấy tập tin mp3 của google về máy thì xem tôi "biểu diễn" trong tập tin. :D

    Em đã test file thầy rất là hay. không phải ghi âm trước. CHo em ví dụ em có 100 bệnh nhân em muốn copy mã số vào vùng B5:B105 rồi nhấn cho nó đọc lần lượt ( B5,b6...B100) để em đi làm chuyện khác chứ . thì em phải thêm For Next vào mục nào hả thầy
    1585882401972.png
     
    Upvote 0
    Hiện tại FPT đã và đang phát triển API để đọc chữ Tiếng Việt và nhận dạng Tiếng Việt qua giọng nói. Giọng đọc của bản v5 khá chuẩn hơn so với v4 trước đó. Tuy nhiên với tk miễn phí thì có giới hạn (10.000 kí tự / request, 60request/ phút).
     
    Upvote 0
    Em đã test file thầy rất là hay. không phải ghi âm trước. CHo em ví dụ em có 100 bệnh nhân em muốn copy mã số vào vùng B5:B105 rồi nhấn cho nó đọc lần lượt ( B5,b6...B100) để em đi làm chuyện khác chứ . thì em phải thêm For Next vào mục nào hả thầy
    -------------------------


    Ở trên tôi đã nói Bác batman1 viết code quá "amater", vì vậy rất khó áp dụng.




    -------------------------
    Code bài trên:
    Copy code dưới thay thế code trong module Player_MCI



    -------------
    JavaScript:
    '                    _,
    ' ___   _   _  _ ___(_)
    '/ __| / \ | \| | _ | |
    '\__ \/ \ \| \\ | _ \ |
    '|___/_/ \_|_|\_|___/_|
    '
    
    'Play Music
    Option Explicit
    #If VBA7 Then
      Private Declare PtrSafe Function SetTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As Long, ByVal lpTimerFunc As LongPtr) As LongPtr
      Private Declare PtrSafe Function KillTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr) As Long
    #Else
      Private Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
      Private Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long
    #End If
    '//////////////////////////////////////////////////////////////
    #If Win64 Then
      Public Glb_TimerID As LongPtr
    #Else
      Public Glb_TimerID As Long
    #End If
    #If VBA7 Then
      Private Declare PtrSafe Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Long, ByVal hwndCallback As Long) As Long
      Private Declare PtrSafe Function mciGetErrorString Lib "winmm.dll" Alias "mciGetErrorStringA" (ByVal dwError As Long, ByVal lpstrBuffer As String, ByVal uLength As Long) As Long
      Private Declare PtrSafe Function GetShortPathName Lib "kernel32" Alias "GetShortPathNameW" (ByVal lpszLongPath As String, ByVal lpszShortPath As String, ByVal cchBuffer As Long) As Long
    #Else
      Private Declare  Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Long, ByVal hwndCallback As Long) As Long
      Private Declare  Function mciGetErrorString Lib "winmm.dll" Alias "mciGetErrorStringA" (ByVal dwError As Long, ByVal lpstrBuffer As String, ByVal uLength As Long) As Long
      Private Declare  Function GetShortPathName Lib "kernel32" Alias "GetShortPathNameW" (ByVal lpszLongPath As String, ByVal lpszShortPath As String, ByVal cchBuffer As Long) As Long
    #End If
    '//////////////////////////////////////////////////////////////////////////////////
    
    Type PlayerPlaying
      CodeName As String
      ItemIndex As Long
      ItemLength As Long
      ItemName As String
      ItemArtor As Long
      List As Variant
      ListCount As Long
      ListIndex As Long
      Loop As Long
      IndexLoop As Long
      Shuffle As Boolean
      Prioritize As Boolean
      Volume As Long
      Speed As Double
      LoopWait As Long
      Position As Long
    End Type
    '//////////////////////////////////////////////////////////////////////////////////
    Private PNP As PlayerPlaying, DoTime As Date
    '//////////////////////////////////////////////////////////////////////////////////
    Private Row As Long, Col As Long
    Public Sub Player_End()
      On Error Resume Next
      If Glb_TimerID <> 0 Then KillTimer 0&, Glb_TimerID
      Application.OnTime DoTime, "'" & ThisWorkbook.Name & "'!Player_DoTime", , False
      Application.OnTime VBA.Now, "'" & ThisWorkbook.Name & "'!CloseAllAudio", , False
      Call CloseAllAudio
      DoTime = 0: Row = 0: Col = 0
      End
    End Sub
    Public Sub MakeFileAndPlay()
      Static Tmp As String
      Dim WS As Worksheet
      Dim Arr(), K, I, Text As String
      Dim RNG As Range, iStep As Long, LR As Long
      Set WS = Worksheets("data")
    
      If Row = 0 Then
        Set RNG = Selection
        If VBA.TypeName(RNG) <> "Range" Then Exit Sub
        Row = RNG.Row: Col = RNG.Column
      Else
        Row = Row + 1
      End If
    
      Const StartColumn = "B"
      Const StartRow = 5
      LR = WS.Range(StartColumn & 1000).End(3).Row
      If Row > LR Then GoTo Ends
    
      If Col <> Columns(StartColumn).Column Or Row < StartRow Or LR < StartRow Then
        Row = 0: Col = 0: Exit Sub
      End If
    
      WS.Range(StartColumn & StartRow).Resize(LR).Interior.Color = VBA.vbWhite
    
      With WS.Range(StartColumn & Row)
        Text = .Value
        .Interior.Color = VBA.vbYellow
      End With
    
      If Text = "" Or Not VBA.IsNumeric(Text) Then GoTo Ends
      If Tmp = "" Then
        Tmp = PATH_SYS_TEMP & "\MCIPlay\"
        CreateFolder Tmp
        ConvertBase64ToFile Tmp & "cau_mo_dau.wma", Base64_File_cau_mo_dau_wma
        ConvertBase64ToFile Tmp & "so_0.wma", Base64_File_so_0_wma
        ConvertBase64ToFile Tmp & "so_1.wma", Base64_File_so_1_wma
        ConvertBase64ToFile Tmp & "so_2.wma", Base64_File_so_2_wma
        ConvertBase64ToFile Tmp & "so_3.wma", [g6].Value
        ConvertBase64ToFile Tmp & "so_4.wma", Base64_File_so_4_wma
        ConvertBase64ToFile Tmp & "so_5.wma", Base64_File_so_5_wma
        ConvertBase64ToFile Tmp & "so_6.wma", Base64_File_so_6_wma
        ConvertBase64ToFile Tmp & "so_7.wma", Base64_File_so_7_wma
        ConvertBase64ToFile Tmp & "so_8.wma", Base64_File_so_8_wma
        ConvertBase64ToFile Tmp & "so_9.wma", Base64_File_so_9_wma
        ConvertBase64ToFile Tmp & "Vui_long_den_quay.wma", Base64_File_cau_ket_wma
      End If
      K = 1: ReDim Preserve Arr(1 To K)
      Arr(1) = Tmp & "cau_mo_dau.wma"
      For I = 1 To Len(Text)
        K = K + 1: ReDim Preserve Arr(1 To K)
        Arr(K) = Tmp & "so_" & VBA.Mid(Text, I, 1) & ".wma"
      Next
      K = K + 1: ReDim Preserve Arr(1 To K)
      Arr(K) = Tmp & "Vui_long_den_quay.wma"
      '------------------------------
      Player_Intialize Arr, _
                       iLoop:=[C5].Value, _
                       Speed:=1.1, _
                       Volume:=100
    Ends:
      If iStep > LR Then Call Player_End
    End Sub
    '==============================================================
    Private Function PATH_SYS_TEMP() As String
      PATH_SYS_TEMP = VBA.IIf(VBA.Environ("tmp") <> "", VBA.Environ("tmp"), VBA.Environ("temp"))
    End Function
    Public Sub Player_Intialize( _
                          ByVal List As Variant, _
                       Optional iLoop As Long = 0, _
                       Optional WaitLoop As Long = 1, _
                       Optional bShuffle As Boolean = False, _
                       Optional Speed As Double = 1.1, _
                       Optional Volume As Byte = 100, _
                 Optional ByVal NewAliasName As String = "FileMusic")
      If Not VBA.IsArray(List) Then Exit Sub
      Dim I As Long, J As Long
      On Error Resume Next
      If Glb_TimerID <> 0 Then KillTimer 0&, Glb_TimerID
      Application.OnTime DoTime, "'" & ThisWorkbook.Name & "'!Player_DoTime", , False
      Application.OnTime VBA.Now, "'" & ThisWorkbook.Name & "'!CloseAllAudio", , False
      Call CloseAllAudio
    Make:
      PNP.List = List
      PNP.Loop = iLoop
      PNP.LoopWait = WaitLoop
      PNP.Shuffle = bShuffle
      PNP.CodeName = NewAliasName
      PNP.Speed = VBA.IIf(Speed < 0.5, 0.5, VBA.IIf(Speed > 4, 4, Speed))
      PNP.Volume = VBA.IIf(Volume < 0, 0, VBA.IIf(Volume > 100, 100, Volume))
      Dim Item, L As Long, NewList()
      For Each Item In PNP.List
        If VBA.TypeName(Item) = "String" And Len(Item) > 5 Then
          L = L + 1
          ReDim Preserve NewList(1 To L)
          NewList(L) = ShortPath(Item)
        End If
      Next
      If L > 0 Then
        PNP.IndexLoop = 0
        PNP.ItemIndex = 0
        PNP.ListCount = L
        PNP.List = NewList
        Application.OnTime VBA.Now, "'" & ThisWorkbook.Name & "'!Player_ListPlayNext"
      End If
    End Sub
    '//////////////////////////////////////////////////////////////////////////////////
    Public Sub Player_ListPlayNext()
      DoEvents
      On Error Resume Next
      If Not VBA.IsArray(PNP.List) Then Call Player_End: Exit Sub
      Dim I As Long, Idx As Long, R As Long
    
      DoTime = VBA.Now
      If PNP.Shuffle Then
        VBA.Randomize
    Rnd: Idx = Int(PNP.ListCount * Rnd + 1)
        If Idx = PNP.ItemIndex Then GoTo Rnd
      Else
        Idx = PNP.ItemIndex + 1
        If Idx > PNP.ListCount Then
          PNP.Speed = 1.5
          Application.Wait VBA.Now + VBA.TimeSerial(0, 0, PNP.LoopWait)
          Idx = 1: PNP.IndexLoop = PNP.IndexLoop + 1
          If PNP.Loop = 0 Or PNP.IndexLoop > PNP.Loop Then DoTime = 0
        End If
      End If
      If DoTime > 0 Then
        PNP.ItemIndex = Idx
        PNP.ItemName = PNP.List(Idx)
        Call FileOpen
        DoTime = (PNP.ItemLength - 1500)
        DoTime = VBA.IIf(DoTime < 1000, 0, DoTime / 1000 / PNP.Speed)
        DoTime = VBA.Now + VBA.TimeSerial(0, 0, DoTime)
        Application.OnTime DoTime, "'" & ThisWorkbook.Name & "'!Player_DoTime"
      Else
        Application.OnTime VBA.Now + VBA.TimeSerial(0, 0, 2), "'" & ThisWorkbook.Name & "'!MakeFileAndPlay"
      End If
    End Sub
    
    
    
    Public Sub FileOpen()
      DoEvents
      Dim lRet&, sError As String * 255
      Call mciSendString("Close all", "", 0, 0)
      Call mciSendString("Close " & PNP.CodeName, "", 0, 0)
      lRet = mciSendString("open """ & PNP.ItemName & """ alias " & PNP.CodeName, "", 0, 0)
      If PNP.Speed <= 0 Then PNP.Speed = 1
      If PNP.Volume <= 0 Then PNP.Volume = 100
      If lRet <> 0 Then mciGetErrorString lRet, sError, 255: Exit Sub
      Call mciSendString("Play " & PNP.CodeName, "", 0, 0)
      Call mciSendString("set " & PNP.CodeName & " Speed " & CStr(Int(PNP.Speed * 1000)), "", 0, 0)
      Call mciSendString("setaudio " & PNP.CodeName & " volume to " & PNP.Volume * 10, "", 0, 0)
      Call mciSendString("Play " & PNP.CodeName, "", 0, 0)
      PNP.ItemLength = AudioGetLength()
    End Sub
    
    
    
    
    Public Sub Player_DoTime()
      If Glb_TimerID <> 0 Then KillTimer 0&, Glb_TimerID
      Glb_TimerID = SetTimer(0&, 0&, 300, AddressOf Player_CheckPlayNext)
    End Sub
    
    Public Sub Player_CheckPlayNext()
      DoEvents
      Dim T1 As Long
      T1 = AudioGetCurPos()
      If T1 = 0 Then If Glb_TimerID <> 0 Then KillTimer 0&, Glb_TimerID
      If T1 >= PNP.ItemLength - 100 Then
        If Glb_TimerID <> 0 Then KillTimer 0&, Glb_TimerID
        Application.OnTime VBA.Now, "'" & ThisWorkbook.Name & "'!Player_ListPlayNext"
      End If
    End Sub
    '//////////////////////////////////////////////////////////////////////////////////
    
    Function AudioGetLength() As Long
        Dim lRet&, S As String * 255: S = VBA.Space(255)
        On Error Resume Next
        lRet = mciSendString("status " & PNP.CodeName & " length", S, 255, 0)
        If lRet = 0 Then AudioGetLength = CLng(S)
    End Function
    '//////////////////////////////////////////////////////////////////////////////////
    Function AudioGetCurPos() As Long
      DoEvents
      Dim lRet&, S As String * 255: S = VBA.Space(255)
      On Error Resume Next
      lRet = mciSendString("status " & PNP.CodeName & " position wait", S, 255, 0)
      If lRet = 0 Then AudioGetCurPos = CLng(S)
    End Function
    
    '//////////////////////////////////////////////////////////////////////////////////
    Sub CloseAllAudio()
      Call mciSendString("Close all", "", 0, 0)
      On Error Resume Next
    End Sub
    '//////////////////////////////////////////////////////////////////////////////////
    Sub ConvertBase64ToFile(strFilePath As String, strBase64 As String)
      If VBA.Dir(strFilePath, vbSystem) <> "" Then Exit Sub
      Const UseBinaryStreamType = 1
      Const SaveWillCreateOrOverwrite = 2
      Dim streamOutput, xmlDoc: Set streamOutput = CreateObject("ADODB.Stream")
      #If Win64 Then
        Set xmlDoc = CreateObject("MSXML2.DOMDocument.6.0")
      #Else
        Set xmlDoc = CreateObject("Microsoft.XMLDOM")
      #End If
      Dim xmlElem: Set xmlElem = xmlDoc.createElement("tmp")
      xmlElem.DataType = "bin.base64"
      xmlElem.Text = strBase64
      streamOutput.Open
      streamOutput.Type = UseBinaryStreamType
      streamOutput.Write = xmlElem.nodeTypedValue
      streamOutput.SaveToFile strFilePath, SaveWillCreateOrOverwrite
      Set streamOutput = Nothing
      Set xmlDoc = Nothing
      Set xmlElem = Nothing
    End Sub
    
    Private Function CreateFolder(ByVal FolderPath As String, Optional ByRef FileSystem As Object) As Boolean
      Dim FolderArray, Tmp$, I As Integer, UB As Integer, tFolder$
      tFolder = FolderPath
      If VBA.Right(tFolder, 1) = "\" Then tFolder = VBA.Left(tFolder, VBA.Len(tFolder) - 1)
      If tFolder Like "\\*\*" Then tFolder = VBA.Strings.Replace(tFolder, "\", "@", 1, 3)
      FolderArray = VBA.Split(tFolder, "\")
      FolderArray(0) = VBA.Strings.Replace(FolderArray(0), "@", "\", 1, 3)
      On Error GoTo Ends
      If FileSystem Is Nothing Then
        Set FileSystem = VBA.CreateObject("Scripting.FileSystemObject")
      End If
      UB = UBound(FolderArray)
      With FileSystem
        For I = 0 To UB
          Tmp = Tmp & FolderArray(I) & "\"
          If Not .FolderExists(Tmp) Then .CreateFolder (Tmp)
          CreateFolder = (I = UB) And Len(FolderArray(I)) > 0 And FolderArray(I) <> " "
        Next
      End With
    Ends:
    End Function
    '//////////////////////////////////////////////////////////////////////////////////
    Function ShortPath(ByVal LongPath As String) As String
      Dim ret&, Buff As String * 512
      ret = GetShortPathName(StrConv(LongPath, 64), Buff, 512)
      ShortPath = Left(StrConv(Buff, 128), ret)
    End Function
     
    Lần chỉnh sửa cuối:
    Upvote 0
    Hiện tại FPT đã và đang phát triển API để đọc chữ Tiếng Việt và nhận dạng Tiếng Việt qua giọng nói. Giọng đọc của bản v5 khá chuẩn hơn so với v4 trước đó. Tuy nhiên với tk miễn phí thì có giới hạn (5.000 kí tự / request, 60request/ phút).
    Không mượt và ngọt như API của Google.
     
    Upvote 0
    Về bài #8 thì sao lại khởi động chrome? Thứ nhất là khởi động trình duyệt sẽ lâu

    --------------------------------

    Hôm trước có một bạn cũng hỏi vấn đề đọc tiếng Việt.

    Và tôi cũng có trả lời bên đấy, rất đầy đủ.

    Nếu bác có thời gian thì ghé qua xem lại

    https://www.giaiphapexcel.com/diend...-tiếng-việt-trong-excel-ạ.148438/#post-959974
     
    Upvote 0
    -------------------------


    Ở trên tôi đã nói Bác batman1 viết code quá "amater", vì vậy rất khó áp dụng.




    -------------------------
    Code bài trên:
    Copy code dưới thay thế code trong module Player_MCI



    -------------
    JavaScript:
    '                    _,
    ' ___   _   _  _ ___(_)
    '/ __| / \ | \| | _ | |
    '\__ \/ \ \| \\ | _ \ |
    '|___/_/ \_|_|\_|___/_|
    '
    
    'Play Music
    Option Explicit
    #If VBA7 Then
      Private Declare PtrSafe Function SetTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As Long, ByVal lpTimerFunc As LongPtr) As LongPtr
      Private Declare PtrSafe Function KillTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr) As Long
    #Else
      Private Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
      Private Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long
    #End If
    '//////////////////////////////////////////////////////////////
    #If Win64 Then
      Public Glb_TimerID As LongPtr
    #Else
      Public Glb_TimerID As Long
    #End If
    #If VBA7 Then
      Private Declare PtrSafe Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Long, ByVal hwndCallback As Long) As Long
      Private Declare PtrSafe Function mciGetErrorString Lib "winmm.dll" Alias "mciGetErrorStringA" (ByVal dwError As Long, ByVal lpstrBuffer As String, ByVal uLength As Long) As Long
      Private Declare PtrSafe Function GetShortPathName Lib "kernel32" Alias "GetShortPathNameW" (ByVal lpszLongPath As String, ByVal lpszShortPath As String, ByVal cchBuffer As Long) As Long
    #Else
      Private Declare  Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Long, ByVal hwndCallback As Long) As Long
      Private Declare  Function mciGetErrorString Lib "winmm.dll" Alias "mciGetErrorStringA" (ByVal dwError As Long, ByVal lpstrBuffer As String, ByVal uLength As Long) As Long
      Private Declare  Function GetShortPathName Lib "kernel32" Alias "GetShortPathNameW" (ByVal lpszLongPath As String, ByVal lpszShortPath As String, ByVal cchBuffer As Long) As Long
    #End If
    '//////////////////////////////////////////////////////////////////////////////////
    
    Type PlayerPlaying
      CodeName As String
      ItemIndex As Long
      ItemLength As Long
      ItemName As String
      ItemArtor As Long
      List As Variant
      ListCount As Long
      ListIndex As Long
      Loop As Long
      IndexLoop As Long
      Shuffle As Boolean
      Prioritize As Boolean
      Volume As Long
      Speed As Double
      LoopWait As Long
      Position As Long
    End Type
    '//////////////////////////////////////////////////////////////////////////////////
    Private PNP As PlayerPlaying, DoTime As Date
    '//////////////////////////////////////////////////////////////////////////////////
    Private Row As Long, Col As Long
    Public Sub Player_End()
      On Error Resume Next
      If Glb_TimerID <> 0 Then KillTimer 0&, Glb_TimerID
      Application.OnTime DoTime, "'" & ThisWorkbook.Name & "'!Player_DoTime", , False
      Application.OnTime VBA.Now, "'" & ThisWorkbook.Name & "'!CloseAllAudio", , False
      Call CloseAllAudio
      DoTime = 0: Row = 0: Col = 0
      End
    End Sub
    Public Sub MakeFileAndPlay()
      Static Tmp As String
      Dim WS As Worksheet
      Dim Arr(), K, I, Text As String
      Dim RNG As Range, iStep As Long, LR As Long
      Set WS = Worksheets("data")
    
      If Row = 0 Then
        Set RNG = Selection
        If VBA.TypeName(RNG) <> "Range" Then Exit Sub
        Row = RNG.Row: Col = RNG.Column
      Else
        Row = Row + 1
      End If
    
      Const StartColumn = "B"
      Const StartRow = 5
      LR = WS.Range(StartColumn & 1000).End(3).Row
      If Row > LR Then GoTo Ends
    
      If Col <> Columns(StartColumn).Column Or Row < StartRow Or LR < StartRow Then
        Row = 0: Col = 0: Exit Sub
      End If
    
      WS.Range(StartColumn & StartRow).Resize(LR).Interior.Color = VBA.vbWhite
    
      With WS.Range(StartColumn & Row)
        Text = .Value
        .Interior.Color = VBA.vbYellow
      End With
    
      If Text = "" Or Not VBA.IsNumeric(Text) Then GoTo Ends
      If Tmp = "" Then
        Tmp = PATH_SYS_TEMP & "\MCIPlay\"
        CreateFolder Tmp
        ConvertBase64ToFile Tmp & "cau_mo_dau.wma", Base64_File_cau_mo_dau_wma
        ConvertBase64ToFile Tmp & "so_0.wma", Base64_File_so_0_wma
        ConvertBase64ToFile Tmp & "so_1.wma", Base64_File_so_1_wma
        ConvertBase64ToFile Tmp & "so_2.wma", Base64_File_so_2_wma
        ConvertBase64ToFile Tmp & "so_3.wma", [g6].Value
        ConvertBase64ToFile Tmp & "so_4.wma", Base64_File_so_4_wma
        ConvertBase64ToFile Tmp & "so_5.wma", Base64_File_so_5_wma
        ConvertBase64ToFile Tmp & "so_6.wma", Base64_File_so_6_wma
        ConvertBase64ToFile Tmp & "so_7.wma", Base64_File_so_7_wma
        ConvertBase64ToFile Tmp & "so_8.wma", Base64_File_so_8_wma
        ConvertBase64ToFile Tmp & "so_9.wma", Base64_File_so_9_wma
        ConvertBase64ToFile Tmp & "Vui_long_den_quay.wma", Base64_File_cau_ket_wma
      End If
      K = 1: ReDim Preserve Arr(1 To K)
      Arr(1) = Tmp & "cau_mo_dau.wma"
      For I = 1 To Len(Text)
        K = K + 1: ReDim Preserve Arr(1 To K)
        Arr(K) = Tmp & "so_" & VBA.Mid(Text, I, 1) & ".wma"
      Next
      K = K + 1: ReDim Preserve Arr(1 To K)
      Arr(K) = Tmp & "Vui_long_den_quay.wma"
      '------------------------------
      Player_Intialize Arr, _
                       iLoop:=[C5].Value, _
                       Speed:=1.1, _
                       Volume:=100
    Ends:
      If iStep > LR Then Call Player_End
    End Sub
    '==============================================================
    Private Function PATH_SYS_TEMP() As String
      PATH_SYS_TEMP = VBA.IIf(VBA.Environ("tmp") <> "", VBA.Environ("tmp"), VBA.Environ("temp"))
    End Function
    Public Sub Player_Intialize( _
                          ByVal List As Variant, _
                       Optional iLoop As Long = 0, _
                       Optional WaitLoop As Long = 1, _
                       Optional bShuffle As Boolean = False, _
                       Optional Speed As Double = 1.1, _
                       Optional Volume As Byte = 100, _
                 Optional ByVal NewAliasName As String = "FileMusic")
      If Not VBA.IsArray(List) Then Exit Sub
      Dim I As Long, J As Long
      On Error Resume Next
      If Glb_TimerID <> 0 Then KillTimer 0&, Glb_TimerID
      Application.OnTime DoTime, "'" & ThisWorkbook.Name & "'!Player_DoTime", , False
      Application.OnTime VBA.Now, "'" & ThisWorkbook.Name & "'!CloseAllAudio", , False
      Call CloseAllAudio
    Make:
      PNP.List = List
      PNP.Loop = iLoop
      PNP.LoopWait = WaitLoop
      PNP.Shuffle = bShuffle
      PNP.CodeName = NewAliasName
      PNP.Speed = VBA.IIf(Speed < 0.5, 0.5, VBA.IIf(Speed > 4, 4, Speed))
      PNP.Volume = VBA.IIf(Volume < 0, 0, VBA.IIf(Volume > 100, 100, Volume))
      Dim Item, L As Long, NewList()
      For Each Item In PNP.List
        If VBA.TypeName(Item) = "String" And Len(Item) > 5 Then
          L = L + 1
          ReDim Preserve NewList(1 To L)
          NewList(L) = ShortPath(Item)
        End If
      Next
      If L > 0 Then
        PNP.IndexLoop = 0
        PNP.ItemIndex = 0
        PNP.ListCount = L
        PNP.List = NewList
        Application.OnTime VBA.Now, "'" & ThisWorkbook.Name & "'!Player_ListPlayNext"
      End If
    End Sub
    '//////////////////////////////////////////////////////////////////////////////////
    Public Sub Player_ListPlayNext()
      DoEvents
      On Error Resume Next
      If Not VBA.IsArray(PNP.List) Then Call Player_End: Exit Sub
      Dim I As Long, Idx As Long, R As Long
    
      DoTime = VBA.Now
      If PNP.Shuffle Then
        VBA.Randomize
    Rnd: Idx = Int(PNP.ListCount * Rnd + 1)
        If Idx = PNP.ItemIndex Then GoTo Rnd
      Else
        Idx = PNP.ItemIndex + 1
        If Idx > PNP.ListCount Then
          PNP.Speed = 1.5
          Application.Wait VBA.Now + VBA.TimeSerial(0, 0, PNP.LoopWait)
          Idx = 1: PNP.IndexLoop = PNP.IndexLoop + 1
          If PNP.Loop = 0 Or PNP.IndexLoop > PNP.Loop Then DoTime = 0
        End If
      End If
      If DoTime > 0 Then
        PNP.ItemIndex = Idx
        PNP.ItemName = PNP.List(Idx)
        Call FileOpen
        DoTime = (PNP.ItemLength - 1500)
        DoTime = VBA.IIf(DoTime < 1000, 0, DoTime / 1000 / PNP.Speed)
        DoTime = VBA.Now + VBA.TimeSerial(0, 0, DoTime)
        Application.OnTime DoTime, "'" & ThisWorkbook.Name & "'!Player_DoTime"
      Else
        Application.OnTime VBA.Now + VBA.TimeSerial(0, 0, 2), "'" & ThisWorkbook.Name & "'!MakeFileAndPlay"
      End If
    End Sub
    
    
    
    Public Sub FileOpen()
      DoEvents
      Dim lRet&, sError As String * 255
      Call mciSendString("Close all", "", 0, 0)
      Call mciSendString("Close " & PNP.CodeName, "", 0, 0)
      lRet = mciSendString("open """ & PNP.ItemName & """ alias " & PNP.CodeName, "", 0, 0)
      If PNP.Speed <= 0 Then PNP.Speed = 1
      If PNP.Volume <= 0 Then PNP.Volume = 100
      If lRet <> 0 Then mciGetErrorString lRet, sError, 255: Exit Sub
      Call mciSendString("Play " & PNP.CodeName, "", 0, 0)
      Call mciSendString("set " & PNP.CodeName & " Speed " & CStr(Int(PNP.Speed * 1000)), "", 0, 0)
      Call mciSendString("setaudio " & PNP.CodeName & " volume to " & PNP.Volume * 10, "", 0, 0)
      Call mciSendString("Play " & PNP.CodeName, "", 0, 0)
      PNP.ItemLength = AudioGetLength()
    End Sub
    
    
    
    
    Public Sub Player_DoTime()
      If Glb_TimerID <> 0 Then KillTimer 0&, Glb_TimerID
      Glb_TimerID = SetTimer(0&, 0&, 300, AddressOf Player_CheckPlayNext)
    End Sub
    
    Public Sub Player_CheckPlayNext()
      DoEvents
      Dim T1 As Long
      T1 = AudioGetCurPos()
      If T1 = 0 Then If Glb_TimerID <> 0 Then KillTimer 0&, Glb_TimerID
      If T1 >= PNP.ItemLength - 100 Then
        If Glb_TimerID <> 0 Then KillTimer 0&, Glb_TimerID
        Application.OnTime VBA.Now, "'" & ThisWorkbook.Name & "'!Player_ListPlayNext"
      End If
    End Sub
    '//////////////////////////////////////////////////////////////////////////////////
    
    Function AudioGetLength() As Long
        Dim lRet&, S As String * 255: S = VBA.Space(255)
        On Error Resume Next
        lRet = mciSendString("status " & PNP.CodeName & " length", S, 255, 0)
        If lRet = 0 Then AudioGetLength = CLng(S)
    End Function
    '//////////////////////////////////////////////////////////////////////////////////
    Function AudioGetCurPos() As Long
      DoEvents
      Dim lRet&, S As String * 255: S = VBA.Space(255)
      On Error Resume Next
      lRet = mciSendString("status " & PNP.CodeName & " position wait", S, 255, 0)
      If lRet = 0 Then AudioGetCurPos = CLng(S)
    End Function
    
    '//////////////////////////////////////////////////////////////////////////////////
    Sub CloseAllAudio()
      Call mciSendString("Close all", "", 0, 0)
      On Error Resume Next
    End Sub
    '//////////////////////////////////////////////////////////////////////////////////
    Sub ConvertBase64ToFile(strFilePath As String, strBase64 As String)
      If VBA.Dir(strFilePath, vbSystem) <> "" Then Exit Sub
      Const UseBinaryStreamType = 1
      Const SaveWillCreateOrOverwrite = 2
      Dim streamOutput, xmlDoc: Set streamOutput = CreateObject("ADODB.Stream")
      #If Win64 Then
        Set xmlDoc = CreateObject("MSXML2.DOMDocument.6.0")
      #Else
        Set xmlDoc = CreateObject("Microsoft.XMLDOM")
      #End If
      Dim xmlElem: Set xmlElem = xmlDoc.createElement("tmp")
      xmlElem.DataType = "bin.base64"
      xmlElem.Text = strBase64
      streamOutput.Open
      streamOutput.Type = UseBinaryStreamType
      streamOutput.Write = xmlElem.nodeTypedValue
      streamOutput.SaveToFile strFilePath, SaveWillCreateOrOverwrite
      Set streamOutput = Nothing
      Set xmlDoc = Nothing
      Set xmlElem = Nothing
    End Sub
    
    Private Function CreateFolder(ByVal FolderPath As String, Optional ByRef FileSystem As Object) As Boolean
      Dim FolderArray, Tmp$, I As Integer, UB As Integer, tFolder$
      tFolder = FolderPath
      If VBA.Right(tFolder, 1) = "\" Then tFolder = VBA.Left(tFolder, VBA.Len(tFolder) - 1)
      If tFolder Like "\\*\*" Then tFolder = VBA.Strings.Replace(tFolder, "\", "@", 1, 3)
      FolderArray = VBA.Split(tFolder, "\")
      FolderArray(0) = VBA.Strings.Replace(FolderArray(0), "@", "\", 1, 3)
      On Error GoTo Ends
      If FileSystem Is Nothing Then
        Set FileSystem = VBA.CreateObject("Scripting.FileSystemObject")
      End If
      UB = UBound(FolderArray)
      With FileSystem
        For I = 0 To UB
          Tmp = Tmp & FolderArray(I) & "\"
          If Not .FolderExists(Tmp) Then .CreateFolder (Tmp)
          CreateFolder = (I = UB) And Len(FolderArray(I)) > 0 And FolderArray(I) <> " "
        Next
      End With
    Ends:
    End Function
    '//////////////////////////////////////////////////////////////////////////////////
    Function ShortPath(ByVal LongPath As String) As String
      Dim ret&, Buff As String * 512
      ret = GetShortPathName(StrConv(LongPath, 64), Buff, 512)
      ShortPath = Left(StrConv(Buff, 128), ret)
    End Function

    đã thay code nó không đọc được luôn anh ơi.
     

    File đính kèm

    Upvote 0
    Bạn đừng có xóa dữ liệu ở cột G
     

    File đính kèm

    Upvote 0
    Bạn đừng có xóa dữ liệu ở cột G

    Xin lỗi,.. bấm hết các nút mà không nghe thấy tiếng gì?tôi không hiểu gì cả?.. cột G là cái gì vậy sao loằng ngoằng thế.
    Tôi tải tập tin bài 13 về chạy có tiếng bình thường, không phải thêm những cái loằng ngoằng như cột G..
    Bài đã được tự động gộp:

    Em đã test file thầy rất là hay. không phải ghi âm trước. CHo em ví dụ em có 100 bệnh nhân em muốn copy mã số vào vùng B5:B105 rồi nhấn cho nó đọc lần lượt ( B5,b6...B100) để em đi làm chuyện khác chứ . thì em phải thêm For Next vào mục nào hả thầy
    View attachment 234616
    Có thể thêm nút "DỪNG ĐỌC" và thêm một ô thời gian cách nhau mỗi số được không Bạn?
    Ví dụ cứ 5 phút là lại đọc tiếp 1 số.. để cho mọi người còn chuẩn bị.
     
    Lần chỉnh sửa cuối:
    Upvote 0
    Xin lỗi,.. bấm hết các nút mà không nghe thấy tiếng gì?tôi không hiểu gì cả?.. cột G là cái gì vậy sao loằng ngoằng thế.
    Tôi tải tập tin bài 13 về chạy có tiếng bình thường, không phải thêm những cái loằng ngoằng như cột G..
    -------------------------------

    Thì bạn cứ dùng bài #13
     
    Upvote 0
    -------------------------------

    Thì bạn cứ dùng bài #13
    Nhìn code của bạn không rõ ràng, cứ như là virut ấy...
    Bạn viết bài thì cũng phải có trách nhiệm một chút với bài viết của mình chứ.
    Tôi cảm giác bạn viết để khoe nhiều hơn là bạn viết để cho mọi người sử dụng, vì bạn không quan tâm đến việc tôi nói là tập tin của bạn tôi không sử dụng được. mà không dùng được thì chắc chắn tôi sẽ dùng tập tin trong bài 13 rồi.. đâu cần bạn phải nhắc..
    Chi bằng thay vì nhắc như vậy bạn nên dành thời gian để xem lại tập tin của bạn.
     
    Upvote 0
    -------------------------


    Ở trên tôi đã nói Bác batman1 viết code quá "amater", vì vậy rất khó áp dụng.
    Tôi trả lời cho một chủ đề cụ thể. Chỉ là đọc 1 số. Tôi không có ý định viết dài như bạn. Vì tôi đã từng viết ít ra là 3, 5 lần. Có đầy đủ các thủ tục open, play, pause, seek, close ... Người dùng chỉ phải tự viết thêm để gọi các thủ tục đó.

    Nếu bạn lặp đi lặp lại là tôi "amater" thì xin chỉ rõ từng điểm để tôi học tập bạn được không? Nói miệng thì ai chả nói được.

    Cái chuyện phát 1 danh sách liên tục là chuyện nhỏ như con thỏ. Tôi còn làm chuyện phát 2, 3 phim cùng lúc, phát cả phim và nhạc cùng lúc cơ. Nhưng chủ đề này người ta chỉ hỏi 1 vấn đề. Người ta hỏi và tôi đọc thấy là bạn chỉ cho vỏn vẹn 1 đoạn code dùng chrome phát audio từ google. Tôi thấy nó quá kém cỏi, vì đơn giản bạn không biết cách lấy mp3 về máy. Nếu biết thì bạn đã không dùng cách củ chuối rồi. Tôi chỉ chăm chú vào 1 việc cụ thể để cho bạn biết thôi. Tôi chỉ vạch ra một cách đi khác cho bài #8 của bạn thôi. Không viết nhiều.
     
    Lần chỉnh sửa cuối:
    Upvote 0
    Nhìn code của bạn không rõ ràng, cứ như là virut ấy...
    Bạn viết bài thì cũng phải có trách nhiệm một chút với bài viết của mình chứ.
    Tôi cảm giác bạn viết để khoe nhiều hơn là bạn viết để cho mọi người sử dụng, vì bạn không quan tâm đến việc tôi nói là tập tin của bạn tôi không sử dụng được. mà không dùng được thì chắc chắn tôi sẽ dùng tập tin trong bài 13 rồi.. đâu cần bạn phải nhắc..
    Chi bằng thay vì nhắc như vậy bạn nên dành thời gian để xem lại tập tin của bạn.
    ----------------------------


    Thì bạn cứ dùng bài #13
    Bài đã được tự động gộp:

    đã thay code nó không đọc được luôn anh ơi.
    -------------------------------------


    Tôi quên hướng dẫn sử dụng

    Bạn để con trỏ vào Ô trong cột B và click Đọc số

    Nó sẽ đọc từ trên xuống
     
    Lần chỉnh sửa cuối:
    Upvote 0
    Web KT

    Bài viết mới nhất

    Back
    Top Bottom